05月17日
一、今日完成情况
- 中兴简历提交
- 通读Pi的源码
二、今日感悟
- 核心业务数据:
- 今日工作总结:
- 明日工作计划:
- 今日学习成长:
三、备注
- 无
四、架构梳理
概览
Pi 是一个基于 ReAct(Reasoning + Acting)框架的代码生成代理项目,采用 monorepo 结构,包含 5 个核心包:
| 包 | 职责 |
|---|---|
| packages/ai | 统一的多提供商 LLM API(OpenAI、Anthropic、Google、Azure 等) |
| packages/agent | Agent 运行时核心,实现 ReAct 循环、工具调用、状态管理 |
| packages/coding-agent | 交互式 CLI 应用,封装 agent 和 ai 包 |
| packages/tui | 终端 UI 库(差分渲染) |
| packages/web-ui | Web 组件 |
ReAct 框架核心实现(packages/agent)
双层循环结构
外部循环 (Outer Loop)
├── 继续条件:followUp 队列有消息
└── 退出:没有 followUp 消息时退出
内部循环 (Inner Loop)
├── 继续条件:hasMoreToolCalls || pendingMessages > 0
├── 处理 steering 消息注入
├── streamAssistantResponse() 获取助手响应
├── executeToolCalls() 执行工具调用
└── 触发 shouldStopAfterTurn 检查
关键设计:AgentMessage → Message[] 转换边界
核心设计理念:在 LLM 调用边界才将 AgentMessage 转换为 Message[]
// agent-loop.ts - streamAssistantResponse()
async function streamAssistantResponse(context, config, ...) {
// 1. 上下文转换(可选)
let messages = context.messages;
if (config.transformContext) {
messages = await config.transformContext(messages, signal);
}
// 2. AgentMessage[] → LLM Message[](关键转换点)
const llmMessages = await config.convertToLlm(messages);
// 3. 调用 LLM
const response = await streamSimple(config.model, { messages: llmMessages, ... }, config);
}
工具执行模式
- 顺序执行:工具串行执行,一个完成再执行下一个
- 并行执行:预检全部工具后,允许的工具并发执行,
tool_execution_end按完成顺序触发
核心类型(types.ts)
AgentMessage:Agent 层面的消息(支持自定义扩展)AgentContext:传递给循环的上下文(systemPrompt、messages、tools)AgentLoopConfig:循环配置(convertToLlm、transformContext、getApiKey、getSteeringMessages、getFollowUpMessages、beforeToolCall、afterToolCall 等)AgentEvent:生命周期事件(agent_start/agent_end、turn_start/turn_end、message_start/message_end、tool_execution_start/update/end)
AI 层架构(packages/ai)
多提供商支持
通过 Api 和 KnownProvider 类型系统支持多种 LLM:
type Api = "openai-completions" | "anthropic-messages" | "bedrock-converse-stream" | ...;
type KnownProvider = "anthropic" | "google" | "openai" | "amazon-bedrock" | ...;
核心导出
streamSimple():简化的流式调用(封装了完整的流处理逻辑)stream():底层流式调用complete()/completeSimple():非流式调用EventStream:基于事件的流处理
Coding Agent 层(packages/coding-agent)
架构层次
src/
├── core/ # 核心模块(Agent、Session、Messages、ModelResolver)
├── cli/ # CLI 参数解析
├── modes/ # 运行模式(交互、打印、RPC)
├── utils/ # 工具函数
└── main.ts # CLI 主逻辑
与下层的关系
// core/sdk.ts
const agent = new Agent({
streamFn: async (model, context, options) => {
return streamSimple(model, context, options);
},
convertToLlm: transformMessages,
// ...
});
状态模型与生命周期
根据 agent-harness.md,AgentHarness 将状态分为:
- Harness Config:运行时配置(model、thinking level、tools、resources)
- Turn Snapshot:单次 LLM 调用使用的快照
- Session:持久化的会话条目
- Pending Session Writes:操作期间排队的写入
关键概念:
phase:操作阶段(idle、turn、compaction、branch_summary、retry)save point:助手回复+工具结果完成后保存快照shouldStopAfterTurn:决定是否继续的钩子
数据流总结
用户输入
↓
coding-agent (CLI) → AgentHarness (高级封装)
↓
agent-loop (ReAct 循环)
├─ getSteeringMessages() / getFollowUpMessages()
├─ transformContext() [可选]
├─ convertToLlm() [AgentMessage → Message]
├─ streamSimple() [调用 LLM]
├─ 处理 tool_calls
└─ shouldStopAfterTurn() / prepareNextTurn()
↓
packages/ai (多提供商 LLM API)
├─ OpenAI
├─ Anthropic
├─ Google
├─ Azure
├─ Amazon Bedrock
└─ ...其他提供商
Pi 不仅仅是对话,它是一个完整的编码代理(coding agent)。
内置工具
从 pi-test.sh --help 可以看到,pi 内置了以下工具:
| 工具 | 功能 |
|---|---|
| read | 读取文件内容 |
| bash | 执行 shell 命令 |
| edit | 编辑文件(修改部分内容) |
| write | 写入/创建文件 |
ReAct 框架的能力
基于 ReAct 循环,pi 可以:
- 理解用户需求(如”帮我修改 README.md 中的某段文字”)
- 调用
read工具读取文件 - 分析内容后决定如何修改
- 调用
edit或write工具修改文件 - 验证修改结果
内置工具位置
| 工具 | 文件路径 |
|---|---|
| read | packages/coding-agent/src/core/tools/read.ts |
| bash | packages/coding-agent/src/core/tools/bash.ts |
| edit | packages/coding-agent/src/core/tools/edit.ts |
| write | packages/coding-agent/src/core/tools/write.ts |
工具注册入口
- 统一导出:
packages/coding-agent/src/core/tools/index.ts - 工具定义创建:在
index.ts中通过createToolDefinition()注册
// packages/coding-agent/src/core/tools/index.ts
export type ToolName = "read" | "bash" | "edit" | "write" | "grep" | "find" | "ls";
工具调用流程
- LLM 返回 tool_call:
packages/ai/src/providers/openai-completions.ts解析 OpenAI 格式的 tool_calls - Agent 循环处理:
packages/agent/src/agent-loop.ts的executeToolCalls() - 工具执行:
packages/coding-agent/src/core/tools/下的各工具文件 - 结果返回 LLM:
ToolResultMessage格式
当前卡住原因
问题在步骤 1:Qwen3 的 qwen3_xml parser 输出的 tool_call 格式与 pi 解析器期望的格式不匹配。
如果你需要调试工具调用,可以查看 packages/ai/src/providers/openai-completions.ts 中的 ensureToolCallBlock() 和工具解析逻辑。
扩展机制
项目还支持通过 packages/coding-agent/src/core/extensions/ 扩展更多工具:
- 内置扩展:
prompt-url-widget.ts,redraws.ts,tps.ts - 支持用户自定义扩展
配置方式
工具可以在启动时配置:
-nt/--no-tools:禁用所有工具-nbt/--no-builtin-tools:禁用内置工具,保留扩展工具-t <tools>:白名单模式,只启用指定工具
简单说:pi 是一个能够读写文件、执行命令、帮你写代码的 AI 助手,不是纯对话聊天机器人。
五、vllm参数 – 工具调用
1、模型启动
Qwen3-32B,正确的工具解析器是:qwen3_xml
脚本启动方式.sh当中的参数修改如下:
exec vllm serve "${MODEL}" \
--host "${HOST}" \
--port "${PORT}" \
--served-model-name "${SERVED_MODEL_NAME}" \
--reasoning-parser qwen3 \
--max-model-len "${MAX_MODEL_LEN}" \
--gpu-memory-utilization "${GPU_MEMORY_UTILIZATION:-0.92}" \
--enable-auto-tool-choice \
--tool-call-parser qwen3_xml
启动xml工具,才可以让大模型可以读取本地的项目或者方案,添加参数之后重新启动:
pkill -f vllm
# 重新启动脚本
/root/Documents/code/python/scripts/serve_qwen3_32b.sh
2、xml格式工具调用
curl -s "https://llm.litearch.cn/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer LITEARCH_LLM_2026_SAFE_KEY" \
-d '{
"model": "Qwen/Qwen3-32B",
"messages": [
{"role": "user", "content": "请读取当前目录下的README.md文件"}
],
"tools": [
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取文件内容",
"parameters": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "文件路径"}
},
"required": ["file_path"]
}
}
}
],
"tool_choice": "auto"
}' | jq .
{
"id": "chatcmpl-9445e83d212c1c4b",
"object": "chat.completion",
"created": 1779007966,
"model": "Qwen/Qwen3-32B",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "\n\n<tool_call>\n{\"name\": \"read_file\", \"arguments\": {\"file_path\": \"README.md\"}}\n</tool_call>",
"refusal": null,
"annotations": null,
"audio": null,
"function_call": null,
"tool_calls": [],
"reasoning": "\n好的,用户让我读取当前目录下的README.md文件。我需要使用提供的read_file工具来完成这个任务。首先,我需要确认工具的参数要求。工具需要一个file_path参数,类型是字符串,描述是文件路径。用户提到的文件是当前目录下的README.md,所以文件路径应该是相对于当前工作目录的。\n\n接下来,我需要确保路径的正确性。如果用户是在项目根目录下执行这个请求,那么路径可能只是“README.md”。但如果当前目录有子目录,可能需要调整路径。不过用户明确说“当前目录下”,所以应该直接使用“README.md”作为文件路径。然后,我需要构造一个符合工具要求的JSON对象,调用read_file函数,参数是file_path: \"README.md\"。最后,将这个调用包装在指定的XML标签中返回。确保没有其他多余的信息,只返回工具调用的部分。\n"
},
"logprobs": null,
"finish_reason": "stop",
"stop_reason": null,
"token_ids": null
}
],
"service_tier": null,
"system_fingerprint": null,
"usage": {
"prompt_tokens": 163,
"total_tokens": 380,
"completion_tokens": 217,
"prompt_tokens_details": null
},
"prompt_logprobs": null,
"prompt_token_ids": null,
"kv_transfer_params": null
}
这是 Qwen3 模型专属的 XML 工具调用格式,证明:
- vLLM 启动参数
--tool-call-parser qwen3_xml正常工作 - 模型成功识别了你的工具请求
"name": "read_file":
模型精准听懂了你的指令:
请读取当前目录下的 README.md 文件
自动选择了 read_file(读取文件工具)
"arguments": {"file_path": "README.md"}:
模型自动填充了正确参数:
- 文件路径:
README.md - 完全符合你定义的工具规则
- 逻辑完全正确
"finish_reason": "stop":
模型正常完成推理,没有报错、没有崩溃、没有卡住
reasoning 字段:
这是模型的思考过程,它明确告诉你:
我要调用 read_file 工具,读取 README.md 文件
六、PI项目.json配置文件
{
"providers": {
"litearch": {
"name": "LiteArch LLM",
"baseUrl": "https://llm.litearch.cn/v1",
"apiKey": "LITEARCH_LLM_2026_SAFE_KEY",
"api": "openai-completions",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false,
"supportsStrictMode": false,
"supportsStore": false,
"thinkingFormat": "qwen"
},
"models": [
{
"id": "Qwen/Qwen3-32B",
"name": "Qwen3-32B",
"reasoning": true,
"contextWindow": 32000,
"maxTokens": 8192
}
]
}
}
}
测试语言模式:
cp .pi/models.json ~/.pi/agent/models.json
./pi-test.sh --provider litearch --model "Qwen/Qwen3-32B" -p "你好,做个自我介绍" -nt
回复答案如下:
(APIServer pid=9693) INFO: 39.144.137.50:0 - "POST /v1/chat/completions HTTP/1.0" 200 OK
I am a coding assistant operating within the pi coding agent harness. My capabilities include:
- Reading/writing files (showing full paths)
- Executing commands in the terminal
- Editing code with type-aware suggestions
- Creating new files and directories
- Following strict development rules for this project
I adhere to your project's guidelines for:
- Code quality (no `any` types, standard imports)
- Git safety (atomic commits, no force pushes)
- Testing (vitest, faux provider)
- Documentation (CHANGELOG format)
I can help with:
- Implementing features
- Debugging issues
- Writing tests
- Maintaining code quality
- Following your contribution workflow
What would you like me to help with today?
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 kipleyarch@gmail.com