Skip to content

feat: add async LLM tool workflows and richer CLI progress - #6

Merged
ztygod merged 3 commits into
mainfrom
refacor/cli-stream
Aug 3, 2026
Merged

feat: add async LLM tool workflows and richer CLI progress#6
ztygod merged 3 commits into
mainfrom
refacor/cli-stream

Conversation

@ztygod

@ztygod ztygod commented Aug 3, 2026

Copy link
Copy Markdown
Owner

概述

本 PR 重构了 NoteForge 的 LLM 调用与 CLI 展示链路,在保持确定性 Pipeline 的基础上,引入受约束的工具调用、异步并发请求和更细粒度的运行状态展示,提升笔记生成流程的稳定性、执行效率与可观测性。

主要改动

CLI 展示

  • 增加 LLM 请求、工具提交、响应校验和失败重试等阶段内部状态
  • 展示当前批次、模型、调用次数、Token 用量和重试次数
  • 支持通过 --llm-concurrency 配置单阶段最大并发批次数
  • 并发请求完成顺序不同时,确保进度条稳定递增

LLM 工具调用

  • 新增 submit_semantic_analysis 工具
  • 新增 submit_knowledge_points 工具
  • 为 OpenAI、Anthropic 和 Ollama 实现统一的工具调用接口
  • 保留普通 JSON 输出作为兼容回退方案
  • 工具返回结果继续经过本地严格校验
  • 校验失败时携带具体错误自动重试一次

异步请求与并发

  • 使用 httpx.AsyncClient 替换同步 HTTP 请求
  • 复用异步 HTTP 连接池
  • 将 LLM Client 和 Provider 接口改为异步调用
  • 使用 asyncio.Semaphore 控制批次并发
  • 使用 asyncio.gather 并发处理批次,同时保持最终结果顺序
  • Pipeline 结束后自动释放 HTTP 连接

DeepSeek V4 兼容

  • 适配 deepseek-v4-flash
  • 工具调用时关闭不兼容强制 tool_choice 的 thinking 模式
  • /beta endpoint 不启用 DeepSeek strict beta 参数
  • 保留本地 Schema 校验作为稳定性保障

类型体系与输出稳定性

  • 明确区分 SemanticChunkTypeKnowledgePointType
  • 将两套类型统一收敛至独立 taxonomy 模块
  • 工具 JSON Schema 直接从领域

@ztygod
ztygod requested a review from Copilot August 3, 2026 09:27
@ztygod
ztygod merged commit e1882a7 into main Aug 3, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors NoteForge’s LLM execution path to support async HTTP, bounded concurrent batch processing, and provider-agnostic tool-calling (with strict local validation + retry), while enhancing CLI progress observability and introducing a shared knowledge taxonomy.

Changes:

  • Migrates LLM providers and transport to async using a reusable httpx.AsyncClient, and adds a unified call_tool() API across providers.
  • Adds bounded concurrency (asyncio.Semaphore) for semantic analysis and knowledge extraction batches, plus richer per-stage activity/progress metrics for the CLI.
  • Introduces shared taxonomy enums and fixed “submit_*” tools with schemas derived from domain enums.

Reviewed changes

Copilot reviewed 29 out of 31 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Adds httpx (and dependencies) to the locked dependency set.
pyproject.toml Declares httpx>=0.28,<1 as a runtime dependency.
README.md Adds a development-stage warning and a CLI screenshot.
README.zh-CN.md Adds a development-stage warning and a CLI screenshot (ZH-CN).
output/BV18fcozAEsy.md Adds a large generated sample output markdown file.
tests/llm/test_llm.py Updates tests for async clients/transports and adds tool-call coverage.
tests/knowledge/semantic/test_semantic.py Adds concurrency + retry behavior tests and adapts to async client API.
tests/knowledge/prompts/test_prompts.py Updates prompt expectations (taxonomy wording + constraints).
tests/knowledge/extraction/test_extraction.py Adds normalization and tool-schema derivation tests; adapts async.
tests/cli/test_renderer.py Verifies RUNNING events carry tool/activity details for renderer display.
tests/cli/test_app.py Updates CLI app test to accommodate async client lifecycle/aclose().
src/noteforge/llm/providers/init.py Replaces urllib transport with async httpx transport and adds aclose().
src/noteforge/llm/providers/openai.py Makes OpenAI provider async; adds call_tool() + DeepSeek compatibility handling.
src/noteforge/llm/providers/ollama.py Makes Ollama provider async and adds call_tool() parsing.
src/noteforge/llm/providers/anthropic.py Makes Anthropic provider async and adds call_tool() parsing.
src/noteforge/llm/models.py Adds provider-agnostic tool types (LLMTool* models).
src/noteforge/llm/base.py Converts base client API to async and adds default tool fallback + aclose().
src/noteforge/llm/init.py Re-exports new tool models.
src/noteforge/knowledge/taxonomy.py Introduces shared SemanticChunkType / KnowledgePointType enums.
src/noteforge/knowledge/tools.py Defines fixed tool schemas for semantic analysis and knowledge point submission.
src/noteforge/knowledge/semantic/models.py Switches to shared taxonomy enum import.
src/noteforge/knowledge/semantic/analyzer.py Adds concurrency, activity events, tool-calling, and validation-retry logic.
src/noteforge/knowledge/prompts/semantic_analysis.py Updates prompt to require tool submission rather than raw JSON output.
src/noteforge/knowledge/prompts/knowledge_extraction.py Updates prompt to use taxonomy-driven allowed types and tool submission.
src/noteforge/knowledge/extraction/models.py Switches to shared taxonomy enum import.
src/noteforge/knowledge/extraction/validation.py Adds point_type alias normalization for common upstream semantic labels.
src/noteforge/knowledge/extraction/extractor.py Adds concurrency, activity events, tool-calling, and validation-retry logic.
src/noteforge/core/pipeline.py Tracks monotonic progress, propagates activity metrics, and wires concurrency through pipeline.
src/noteforge/cli/renderer.py Renders richer per-stage RUNNING activity (operation/tool/attempt/model/tokens).
src/noteforge/cli/commands/generate.py Adds --llm-concurrency and ensures client.aclose() after run.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/noteforge/llm/base.py


class LLMClient(ABC):
"""所有模型供应商必须实现的统一同步接口。"""
Comment on lines 54 to +59
self._progress_handler = progress_handler
self._activity_handler = activity_handler
self._max_attempts = max_attempts
if isinstance(max_concurrency, bool) or not isinstance(max_concurrency, int) or max_concurrency <= 0:
raise ValueError("max_concurrency 必须是正整数")
self._max_concurrency = max_concurrency
Comment thread output/BV18fcozAEsy.md
Comment on lines +1 to +3
# 固件学习笔记

> 本文档整理了 71 个知识点,涵盖基础概念、核心原理、工作流程、示例解析、对比分析、其他知识。
Comment on lines 57 to +62
self._progress_handler = progress_handler
self._activity_handler = activity_handler
self._max_attempts = max_attempts
if isinstance(max_concurrency, bool) or not isinstance(max_concurrency, int) or max_concurrency <= 0:
raise ValueError("max_concurrency 必须是正整数")
self._max_concurrency = max_concurrency
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants