最近在尝试从 0 写类似 Claude-Code 的工具,实现长任务运行,由于 Claude-Code,想着探究一下 Claude-Code 底层实现。
1. 前置
实现一个 LLM Proxy,监听端口 8888
如下基于 openai 的模型转换为 Anthropic 的协议,具体代码在文章的最后(用 AI 实现)。
python
# =====================================================================
# Anthropic (Claude) 兼容 --- POST /api/v1/messages
# 参考:https://docs.anthropic.com/en/api/messages
# =====================================================================
# ----- 请求模型 -----
class ClaudeContentBlock(BaseModel):
"""Claude content block(text / image / tool_use / tool_result)"""
type: str
text: Optional[str] = None
# image
source: Optional[dict] = None
# tool_use
id: Optional[str] = None
name: Optional[str] = None
input: Optional[Any] = None
# tool_result
tool_use_id: Optional[str] = None
content: Optional[Any] = None# str 或 list[content block]
is_error: Optional[bool] = None
class ClaudeMessage(BaseModel):
"""Claude 消息"""
role: str
content: str | list[ClaudeContentBlock]
class ClaudeToolInputSchema(BaseModel):
"""Claude tool input_schema"""
type: str = "object"
properties: Optional[dict] = None
required: Optional[list[str]] = None
class ClaudeToolDef(BaseModel):
"""Claude tool 定义"""
name: str
description: Optional[str] = None
input_schema: Optional[ClaudeToolInputSchema | dict] = None
class ClaudeMessagesRequest(BaseModel):
"""Anthropic Messages API 请求格式"""
model: str
messages: list[ClaudeMessage]
max_tokens: int = 4096
system: Optional[str | list[dict]] = None
temperature: Optional[float] = None
top_p: Optional[float] = None
top_k: Optional[int] = None
stop_sequences: Optional[list[str]] = None
stream: Optional[bool] = False
tools: Optional[list[ClaudeToolDef]] = None
tool_choice: Optional[dict] = None
metadata: Optional[dict] = None
# ----- 响应模型 -----
class ClaudeTextBlock(BaseModel):
"""Claude 响应 text block"""
type: str = "text"
text: str
class ClaudeToolUseBlock(BaseModel):
"""Claude 响应 tool_use block"""
type: str = "tool_use"
id: str
name: str
input: dict
class ClaudeUsage(BaseModel):
"""Claude token 用量"""
input_tokens: int = 0
output_tokens: int = 0
class ClaudeMessagesResponse(BaseModel):
"""Anthropic Messages API 响应格式"""
id: str = Field(default_factory=lambda: f"msg_{uuid.uuid4().hex[:24]}")
type: str = "message"
role: str = "assistant"
content: list[dict]
model: str = ""
stop_reason: Optional[str] = "end_turn"
stop_sequence: Optional[str] = None
usage: ClaudeUsage = ClaudeUsage()
...
安装 mitmproxy 启动抓包
perl
mitmproxy --mode reverse:http://localhost:8888 -p 8889
将 proxy 设置 8889,大模型调用到 8889 端口即可
安装 cc-switch
bash
https://github.com/farion1231/cc-switch

2. 开始 Claude-Code
先清空会话或者开始一个新项目开始对话
对话原文:
bash
> 你是什么模型
⏺ 我是 Claude Sonnet 4.6,由 Anthropic 开发的人工智能模型。我是 Claude Code 的底层模型,这是一个专门用于软件工程任务的交互式代理。
我现在正在帮助您处理 /Volumes/my/autosearch_agno 目录下的项目。从 git 状态来看,这是一个新项目,有很多未跟踪的文件(README.md、analysis.ipynb、prepare.py、program.md 等)。
有什么可以帮助您的吗?
> 你有什么技能
⏺ 我是 Claude Code,Anthropic 官方的 Claude CLI 工具,专门用于软件工程任务。我的主要技能包括:
代码相关技能
- 代码编写和修改:创建、编辑、重构代码
- 代码审查和优化:分析代码质量,发现并修复问题
- 调试和故障排除:定位和解决代码中的问题
- 代码解释:分析现有代码并解释其工作原理
开发工具集成
- 文件操作:读取、写入、搜索文件
- Git 操作:查看状态、提交、分支管理等
- Shell 命令执行:运行系统命令和终端操作
- 包管理:处理依赖关系和项目配置
项目管理和探索
- 任务管理:使用 TaskCreate 工具规划和跟踪工作
- 代码库探索:使用 Agent 工具进行深度代码库研究
- 模式识别:发现代码中的模式和惯例
自动化工具
- 技能调用:使用 /simplify 等预定义技能
- 配置管理:使用 /update-config 配置 Claude Code 设置
- 循环任务:使用 /loop 设置定期执行的任务
特定领域
- Claude API 开发:构建使用 Claude API 或 Anthropic SDK 的应用
- 安全测试:在授权范围内进行安全测试和CTF挑战
- 教育指导:帮助学习编程概念和技术
我可以帮助您处理当前项目中的各种任务,比如:
- 分析代码结构和依赖关系
- 实现新功能或修复 bug
- 设置开发环境
- 编写测试
- 优化性能
您希望我从什么开始帮助您?
> 分析当前 readme.md,用中文翻译一份 readme_zh.md
⏺ 我来分析当前的 README.md 文件并创建中文翻译版本。
首先,让我读取当前的 README.md 文件。
....
第一个请求


system提示词
x-anthropic-billing-header: cc_version=2.1.81.dd2; cc_entrypoint=cli; cch=6b09e;: 请求的元信息-
- 计费标识
- 客户端版本标识
- 入口来源
- cch 应该是用于追踪会话的
Generate a concise, sentence-case title (3-7 words) ...: 中文翻译大概是请为这次编程会话生成一个简洁的标题,长度 3 到 7 个词,概括本次会话的主要主题或目标。标题应该足够清晰,让用户在会话列表中一眼识别。使用 sentence case,也就是只有第一个词和专有名词首字母大写。,做这个的目的是重新进入 claude 可以看到你上次对话的标题,方便选择。
第一个回复

- 对应的 SSE 流式输出,这里就是回复的信息,可以忽略。
3、加载 skills 和前置声明
system-reminder

<system-reminder>...</system-reminder>这里表示本地有哪些 skill 可以使用,比如系统自带的:-
- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors ("from now on when X", "each time X", "whenever X", "before/after X") require hooks configured in settings.json --- the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions ("allow X", "add permission", "move permission to"), env vars ("set X=Y"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: "allow npm commands", "add bash permission to global settings", "move permission to user settings", "set DEBUG=true", "when claude stops show X". For simple settings like theme/model, use Config tool.
- simplify: Review changed code for reuse, quality, and efficiency, then fix any issues found.
- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo, defaults to 10m). When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. "check the deploy every 5 minutes", "keep running /babysit-prs"). Do NOT invoke for one-off tasks.
- claude-api: Build apps with the Claude API or Anthropic SDK.\nTRIGGER when: code imports 'anthropic', '@anthropic-ai/sdk', or 'claude_agent_sdk', or user asks to use Claude API, Anthropic SDKs, or Agent SDK.\nDO NOT TRIGGER when: code imports 'openai', other AI SDK, general programming, or ML/data-science tasks.
- 中文解释:
-
- update-config: 通过 settings.json 自动修改 Claude Code 的运行配置,主要是用于权限,环境变量和Hooks 等
- simplify: 用于代码 review 的,让代码更加简洁
- loop: 循环执行 / 定时重复执行的任务,可以通过 Claude Code 选择当前 skill 完成非一次性的任务
- claude-api: 主要用 Claude API 或 Anthropic SDK 来开发应用
IMPORTANT 和 最前置的声明
As you answer the user's questions, you can use the following context:\n# currentDate\nToday's date is 2026-03-24.\n\nThis context may or may not be relevant to your tasks. You should not respond to this context unless it is highly relevant to your task.通过这段话来补充当前时间和背景。IMPORTANT主要是强调用户输入。
System Prompt


如上是 Claude Code 的系统提示词,通过这些指令,我们可以看到 Claude Code 的核心运行逻辑和行为边界,如果包括如下几个声明。
身份与安全边界
- 你是 Claude Code,Anthropic 官方 CLI
- 你是一个帮助用户完成软件工程任务的交互式代理
- 只允许帮助处理:
-
- 授权安全测试
- 防御性安全任务
- CTF
- 教学场景
- 明确拒绝:
-
- 破坏性攻击
- DoS
- 大规模攻击
- 供应链攻击
- 恶意规避检测
URL 与外部资源
- 不要随意编造 URL
- 只有在确信 URL 有助于编程任务时,才能提供
- 如果是用户提供的 URL,可以使用
与用户沟通
- 所有非工具输出都会直接显示给用户
- 可使用 Markdown
- 如果工具被权限模式拦截,用户可能会批准或拒绝
- 如果被拒绝,不要无脑重复同一个调用
- 如果需要用户自己执行命令,可以建议他们输入
! <command>
执行任务的原则
- 用户主要是在让你处理软件工程问题
- 回答要结合当前工作目录和代码库上下文
- 不要在没读过代码的情况下就乱提修改建议
- 除非必要,不要新建文件
- 不要过度设计
- 只做用户明确要求或明显必要的事
- 不要顺手加功能、重构、注释、兼容层、特性开关等多余内容
- 如果发现你写出了不安全代码,要立即修正
风险操作
- 本地、可回退的小修改通常可以直接做
- 对于以下行为要谨慎,通常要先确认:
-
- 删除文件
- 强制推送
- 覆盖未提交修改
- 修改共享基础设施
- 往第三方平台发内容
- 修改 CI/CD
- 核心原则:
-
- 先确认范围,再动手
- 不要用破坏性手段偷懒
工具使用规则
- 有专用工具时,不要乱用 Bash 替代
- 例如:
-
- 读文件用
Read - 改文件用
Edit - 新建文件用
Write - 查文件用
Glob - 搜内容用
Grep
- 读文件用
- 复杂任务要善用任务列表和子代理
- 能并行的工具调用尽量并行
风格要求
- 不要乱用 emoji
- 回复要简短直接
- 引用代码时尽量给出
file_path:line_number - 不要写很多铺垫废话
输出效率
- 直奔主题
- 优先给结果或动作
- 只在这些情况多说一点:
-
- 需要用户做决定
- 自然进度更新
- 出现阻塞或错误
自动记忆
- Claude Code 有持久化 memory 目录
- 需要把稳定模式、用户偏好、架构信息、已验证经验写进去
- 不要写临时状态、未验证信息或当前会话的一次性细节
环境信息
环境部分大意是:
- 当前工作目录:
/Volumes/my/autosearch_agno - 这是一个 Git 仓库
- 平台:darwin
- shell:zsh
- 模型:Claude Sonnet 4.6
- 当前分支:
main - Git 状态里有若干未跟踪文件
4、tools




以上都是一些工具的使用声明和参数,这里有很多就没贴了,大体就是:
- 每个工具是做什么的
- 什么时候该用
- 什么时候不该用
- 参数结构是什么
- 执行时有哪些限制和最佳实践
工具详解
(1) Agent --- 启动子代理
用途:启动新的代理(子进程)来自主处理复杂的多步骤任务。
可用代理类型:
| 代理类型 | 说明 | 可用工具 |
|---|---|---|
general-purpose |
通用代理,用于研究复杂问题、搜索代码、执行多步骤任务 | 全部工具 (*) |
statusline-setup |
配置用户的 Claude Code 状态行设置 | Read, Edit |
Explore |
快速探索代码库,支持 quick/medium/very thorough 三级 | 除 Agent, ExitPlanMode, Edit, Write, NotebookEdit 外的所有工具 |
Plan |
软件架构师代理,设计实现计划 | 除 Agent, ExitPlanMode, Edit, Write, NotebookEdit 外的所有工具 |
claude-code-guide |
回答关于 Claude Code CLI / Agent SDK / Claude API 的问题 | Glob, Grep, Read, WebFetch, WebSearch |
参数(input_schema) :
css
{
"properties": {
"description": {
"description": "A short (3-5 word) description of the task",
"type": "string"
},
"prompt": {
"description": "The task for the agent to perform",
"type": "string"
},
"subagent_type": {
"description": "The type of specialized agent to use for this task",
"type": "string"
},
"model": {
"description": "Optional model override (sonnet/opus/haiku)",
"type": "string",
"enum": ["sonnet", "opus", "haiku"]
},
"run_in_background": {
"description": "Set to true to run this agent in the background",
"type": "boolean"
},
"isolation": {
"description": "Isolation mode. 'worktree' creates a temporary git worktree",
"type": "string",
"enum": ["worktree"]
}
}
}
关键使用规则:
- 尽量并发启动多个独立的 Agent(单条消息中包含多个 tool use)
- 前台(默认):需要结果才能继续时使用;后台:有独立并行工作时使用
- 用
SendMessage继续已有 Agent 的对话 - Agent 的返回结果对用户不可见,需手动汇总转述
(2) TaskOutput --- 获取任务输出
用途:获取正在运行或已完成的后台任务(后台 shell、代理、远程会话)的输出。
参数(input_schema) :
json
{
"properties": {
"task_id": {
"description": "The task ID to get output from",
"type": "string"
},
"block": {
"description": "Whether to wait for completion",
"default": true,
"type": "boolean"
},
"timeout": {
"description": "Max wait time in ms",
"default": 30000,
"type": "number",
"minimum": 0,
"maximum": 600000
}
},
"required": ["task_id", "block", "timeout"]
}
关键使用规则:
block=true(默认)等待任务完成block=false非阻塞检查当前状态- 任务 ID 可通过
/tasks命令获取
(3) Bash --- 执行 Shell 命令
用途:执行 bash 命令并返回输出。工作目录在命令间持久化,但 shell 状态不持久化。
参数(input_schema) :
json
{
"properties": {
"command": {
"description": "The command to execute",
"type": "string"
},
"timeout": {
"description": "Optional timeout in milliseconds (max 600000)",
"type": "number"
},
"description": {
"description": "Clear, concise description of what this command does",
"type": "string"
},
"run_in_background": {
"description": "Set to true to run in background. Use TaskOutput to read output later.",
"type": "boolean"
},
"dangerouslyDisableSandbox": {
"description": "Override sandbox mode and run without sandboxing",
"type": "boolean"
}
},
"required": ["command"]
}
关键使用规则:
- ⚠️ 避免使用
find/grep/cat/head/tail/sed/awk/echo,应使用对应专用工具(Glob/Grep/Read/Edit/Write) - 独立命令并行调用(单条消息多个 Bash tool call);依赖命令用
&&串联 - 默认超时 120s(2 分钟),最大 600s(10 分钟)
- 尽量使用绝对路径,避免
cd - Git 安全协议:不更新 git config、不执行破坏性命令、不跳过 hooks、不 force push main/master
- 创建 commit 时:先
git status+git diff+git log,再起草 commit message - 创建 PR 时:用
gh pr create,包含 Summary 和 Test plan
(4) Glob --- 文件模式匹配
用途:快速文件模式匹配工具,支持任意代码库大小,返回按修改时间排序的匹配文件路径。
参数(input_schema) :
json
{
"properties": {
"pattern": {
"description": "The glob pattern to match files against",
"type": "string"
},
"path": {
"description": "The directory to search in (omit for current working directory)",
"type": "string"
}
},
"required": ["pattern"]
}
关键使用规则:
- 支持
**/*.js、src/**/*.ts等 glob 模式 - 开放式搜索需要多轮时,改用 Agent 工具
- 可并行发起多个 Glob 搜索
(5) Grep --- 内容搜索
用途:基于 ripgrep 的强大搜索工具,支持完整正则语法。
参数(input_schema) :
json
{
"properties": {
"pattern": {
"description": "The regex pattern to search for in files",
"type": "string"
},
"path": {
"description": "The directory to search in (omit for current working directory)",
"type": "string"
},
"include": {
"description": "Glob pattern(s) to filter files (e.g., '*.js', '**/*.tsx')",
"type": "array",
"items": { "type": "string" }
},
"type": {
"description": "Filter files by language/type (e.g., 'js', 'py', 'rust')",
"type": "array",
"items": { "type": "string" }
},
"output": {
"description": "Output mode: 'content' | 'files_with_matches' (default) | 'count'",
"type": "string",
"enum": ["content", "files_with_matches", "count"]
},
"multiline": {
"description": "Enable multiline matching (default false)",
"type": "boolean"
}
},
"required": ["pattern"]
}
关键使用规则:
- ⚠️ 永远不要 通过 Bash 调用
grep或rg,始终使用 Grep 工具 - 使用 ripgrep 语法(非传统 grep),字面量花括号需转义
- 默认输出模式为
files_with_matches(仅文件路径) - 跨行匹配需设置
multiline: true
(6) Read --- 读取文件
用途:从本地文件系统读取文件,支持文本、图片、PDF、Jupyter Notebook。
参数(input_schema) :
json
{
"properties": {
"file_path": {
"description": "The absolute path to the file to read",
"type": "string"
},
"offset": {
"description": "The line number to start reading from (for large files)",
"type": "number"
},
"limit": {
"description": "The number of lines to read (for large files)",
"type": "number"
},
"pages": {
"description": "Page range for PDF files (e.g., '1-5', '3', '10-20'). Max 20 pages/request.",
"type": "string"
}
},
"required": ["file_path"]
}
关键使用规则:
- 路径必须是绝对路径
- 默认读取前 2000 行
- 支持读取图片(PNG/JPG 等,多模态展示)
- PDF 超过 10 页必须 指定
pages参数 - 只能读文件不能读目录(读目录用 Bash 的
ls) - 可并行读取多个文件
(7) Edit --- 编辑文件
用途:在文件中执行精确的字符串替换。
参数(input_schema) :
json
{
"properties": {
"file_path": {
"description": "The absolute path to the file to modify",
"type": "string"
},
"old_string": {
"description": "The text to replace",
"type": "string"
},
"new_string": {
"description": "The text to replace it with (must be different from old_string)",
"type": "string"
},
"replace_all": {
"description": "Replace all occurrences of old_string (default false)",
"default": false,
"type": "boolean"
}
},
"required": ["file_path", "old_string", "new_string"]
}
关键使用规则:
- ⚠️ 编辑前必须先用 Read 工具读取过该文件
- 如果
old_string在文件中不唯一,编辑会失败(需提供更多上下文或用replace_all) - 保持精确的缩进(tab/空格)
- 优先编辑现有文件,不要随意创建新文件
- 不要添加 emoji(除非用户明确要求)
(8) Write --- 写入文件
用途:向本地文件系统写入文件(会覆盖已有文件)。
参数(input_schema) :
css
{
"properties": {
"file_path": {
"description": "The absolute path to the file to write (must be absolute)",
"type": "string"
},
"content": {
"description": "The content to write to the file",
"type": "string"
}
},
"required": ["file_path", "content"]
}
关键使用规则:
- 已有文件必须先 Read 再 Write
- 优先用 Edit 修改现有文件(只发送 diff),Write 仅用于创建新文件或完全重写
- 不要 创建
*.md或 README 文件(除非用户明确要求) - 不要添加 emoji(除非用户明确要求)
(9) NotebookEdit --- 编辑 Jupyter Notebook
用途 :替换/插入/删除 Jupyter Notebook(.ipynb)中特定单元格的内容。
参数(input_schema) :
json
{
"properties": {
"notebook_path": {
"description": "The absolute path to the Jupyter notebook file (must be absolute)",
"type": "string"
},
"cell_number": {
"description": "The 0-indexed number of the cell to edit/insert/delete",
"type": "integer"
},
"new_source": {
"description": "The new source content (required for replace, ignored for delete)",
"type": "string"
},
"edit_mode": {
"description": "Operation mode: 'replace' (default), 'insert', or 'delete'",
"type": "string",
"enum": ["replace", "insert", "delete"]
}
},
"required": ["notebook_path", "cell_number", "edit_mode"]
}
(10) WebFetch --- 抓取网页内容
用途:从 URL 获取内容,转换 HTML 为 markdown,并用小型快速模型处理内容。
参数(input_schema) :
json
{
"properties": {
"url": {
"description": "The URL to fetch content from",
"type": "string",
"format": "uri"
},
"prompt": {
"description": "The prompt to run on the fetched content",
"type": "string"
}
},
"required": ["url", "prompt"]
}
关键使用规则:
- ⚠️ 无法访问需要认证的 URL(Google Docs、Confluence、Jira、GitHub 等),应使用对应 MCP 工具
- HTTP 自动升级为 HTTPS
- 有 15 分钟缓存
- GitHub URL 优先使用
ghCLI - 如有 MCP 提供的 web fetch 工具,优先使用 MCP 版本
(11) WebSearch --- 网页搜索
用途:搜索网页并使用结果来辅助回答,提供超出知识截止日期的最新信息。
参数(input_schema) :
json
{
"properties": {
"query": {
"description": "The search query",
"type": "string"
},
"domain_filter": {
"description": "Domain filtering to include or block specific websites",
"type": "array",
"items": { "type": "string" }
}
},
"required": ["query"]
}
关键使用规则:
- ⚠️ 强制要求 :回答后必须附带
Sources:部分,列出所有相关 URL - 支持域名过滤
- 搜索查询中使用正确的年份
(12) AskUserQuestion --- 向用户提问
用途:在执行过程中向用户提问,收集偏好、澄清指令、获取实现选择的决策。
参数(input_schema) :
css
{
"properties": {
"questions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"text": {
"description": "The question text to show the user",
"type": "string"
},
"options": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": { "type": "string" },
"value": { "type": "string" },
"preview": {
"description": "Optional markdown preview for visual comparison",
"type": "string"
}
},
"required": ["label", "value"]
}
},
"multiSelect": {
"description": "Allow multiple answers (default false)",
"type": "boolean"
}
},
"required": ["id", "text", "options"]
}
}
},
"required": ["questions"]
}
关键使用规则:
- 用户始终可以选择 "Other" 提供自定义输入
- 推荐选项放第一个,末尾加
(Recommended) preview字段仅支持单选(非 multiSelect),用于展示 ASCII 布局、代码片段等- 在 Plan 模式中,不要 用此工具询问"计划是否 OK",应使用
ExitPlanMode
(13) Skill --- 调用技能
用途:调用已注册的技能(Skills)来扩展能力。
可用技能:
| 技能名称 | 触发场景 |
|---|---|
update-config |
配置 settings.json(hooks、权限、环境变量等) |
simplify |
审查已修改代码的复用性、质量、效率 |
loop |
在循环间隔上运行提示或斜杠命令(如 /loop 5m /foo) |
claude-api |
构建使用 Claude API / Anthropic SDK 的应用 |
(14) TaskCreate --- 创建任务
用途 :创建后台任务(如后台 shell 命令、异步代理等)。通常与 TaskOutput 配合使用。
(15) TaskUpdate --- 更新任务
用途:更新已有任务的状态或参数。
(16) TaskList --- 列出任务
用途 :列出所有当前任务及其状态。等同于 /tasks 命令。
(17) EnterPlanMode --- 进入计划模式
用途 :进入计划模式,开始为代码实现任务编写计划。与 ExitPlanMode 配对使用。
相关工具 --- ExitPlanMode:
json
{
"properties": {
"allowedPrompts": {
"description": "Prompt-based permissions needed to implement the plan",
"type": "array",
"items": {
"type": "object",
"properties": {
"tool": {
"description": "The tool this prompt applies to",
"type": "string",
"enum": ["Bash"]
},
"prompt": {
"description": "Semantic description of the action (e.g., 'run tests')",
"type": "string"
}
},
"required": ["tool", "prompt"]
}
}
},
"required": ["allowedPrompts"]
}
关键使用规则:
- 仅在需要编写代码的实现计划时使用(研究任务不用)
- 计划内容写入计划文件,ExitPlanMode 从文件读取
- 不要用 AskUserQuestion 代替 ExitPlanMode 来请求审批
(18) EnterWorktree --- 进入工作树
用途:创建临时 git worktree,在隔离的仓库副本中工作。
(19) CronCreate --- 创建定时任务
用途:创建定时/循环执行的任务。
(20) CronDelete --- 删除定时任务
用途:删除已创建的定时任务。
(21) CronList --- 列出定时任务
用途:列出所有已创建的定时任务。
(22) TaskStop --- 停止任务
用途:停止正在运行的后台任务。
参数(input_schema) :
json
{
"properties": {
"task_id": {
"description": "The ID of the background task to stop",
"type": "string"
},
"shell_id": {
"description": "Deprecated: use task_id instead",
"type": "string"
}
}
}
工具使用优先级速查
| 需求 | ❌ 不要用 | ✅ 应该用 |
|---|---|---|
| 搜索文件 | find, ls (Bash) |
Glob |
| 搜索内容 | grep, rg (Bash) |
Grep |
| 读取文件 | cat, head, tail (Bash) |
Read |
| 编辑文件 | sed, awk (Bash) |
Edit |
| 写入文件 | echo >, cat <<EOF (Bash) |
Write |
| 输出文本 | echo, printf (Bash) |
直接输出文本 |
5、Claude-Code 识别用户意图


在整个任务完成以后,Claude-Code 会预测用户下一步的行为,所以会多发一条请求,大体的就是:
【建议模式:建议用户接下来可能会自然地在 Claude Code 里输入什么。】
首先: 查看用户最近的消息和最初的请求。
你的工作是预测用户自己会输入什么,而不是你觉得他们"应该"做什么。
判断标准:
用户看到后会不会觉得: "对,我刚刚正准备输入这个。"
示例
- 用户说"修复这个 bug 并运行测试",bug 已修好 → 运行测试
- 代码写完后 → 试一下
- Claude 提供了几个选项 → 根据上下文,建议用户最可能会选的那个
- Claude 询问是否继续 → 是 / 继续
- 任务完成后,明显的下一步 → 提交这个 / 推送上去
- 出现错误或误解之后 → 保持沉默(让用户自己评估或纠正)
信息要具体
- "运行测试" 比 "继续" 更好。
绝对不要建议
- 评价性的话(如"看起来不错"、"谢谢")
- 提问(如"那......怎么办?")
- Claude 口吻的话(如"让我来......"、"我会......"、"这是......")
- 用户没有提过的新想法
- 多句话
如果根据用户的话,下一步并不明显,就保持沉默。
格式要求
- 2 到 12 个词
- 匹配用户的说话风格
- 或者什么都不输出
回复时只输出建议内容,不要加引号,也不要解释。
6、Claude-Code 的设计哲学给我们什么启示?
可以看到 Claude-Code 的提示词中没有用什么 RAG 或者复杂的工具,就是日常的工具的组合,搜索就 Glob + Grep,极简的哲学和 Unix 的 一切皆为文件 的思考方式感觉一样。
底层(模型)做的更强大,应用层应用要做更薄。对应到 Harness Engineering,就是所有的实现交给模型+工具,工程师只要设计目标,约束和验证方案即可。
参考
- www.cnblogs.com/noonafter/p...
- juejin.cn/post/761420...
- OpenAI 的模型兼容 Anthropic 的 Proxy 代码:
python
# =====================================================================
# Anthropic (Claude) 兼容 --- POST /api/v1/messages
# 参考:https://docs.anthropic.com/en/api/messages
# =====================================================================
# ----- 请求模型 -----
class ClaudeContentBlock(BaseModel):
"""Claude content block(text / image / tool_use / tool_result)"""
type: str
text: Optional[str] = None
# image
source: Optional[dict] = None
# tool_use
id: Optional[str] = None
name: Optional[str] = None
input: Optional[Any] = None
# tool_result
tool_use_id: Optional[str] = None
content: Optional[Any] = None# str 或 list[content block]
is_error: Optional[bool] = None
class ClaudeMessage(BaseModel):
"""Claude 消息"""
role: str
content: str | list[ClaudeContentBlock]
class ClaudeToolInputSchema(BaseModel):
"""Claude tool input_schema"""
type: str = "object"
properties: Optional[dict] = None
required: Optional[list[str]] = None
class ClaudeToolDef(BaseModel):
"""Claude tool 定义"""
name: str
description: Optional[str] = None
input_schema: Optional[ClaudeToolInputSchema | dict] = None
class ClaudeMessagesRequest(BaseModel):
"""Anthropic Messages API 请求格式"""
model: str
messages: list[ClaudeMessage]
max_tokens: int = 4096
system: Optional[str | list[dict]] = None
temperature: Optional[float] = None
top_p: Optional[float] = None
top_k: Optional[int] = None
stop_sequences: Optional[list[str]] = None
stream: Optional[bool] = False
tools: Optional[list[ClaudeToolDef]] = None
tool_choice: Optional[dict] = None
metadata: Optional[dict] = None
# ----- 响应模型 -----
class ClaudeTextBlock(BaseModel):
"""Claude 响应 text block"""
type: str = "text"
text: str
class ClaudeToolUseBlock(BaseModel):
"""Claude 响应 tool_use block"""
type: str = "tool_use"
id: str
name: str
input: dict
class ClaudeUsage(BaseModel):
"""Claude token 用量"""
input_tokens: int = 0
output_tokens: int = 0
class ClaudeMessagesResponse(BaseModel):
"""Anthropic Messages API 响应格式"""
id: str = Field(default_factory=lambda: f"msg_{uuid.uuid4().hex[:24]}")
type: str = "message"
role: str = "assistant"
content: list[dict]
model: str = ""
stop_reason: Optional[str] = "end_turn"
stop_sequence: Optional[str] = None
usage: ClaudeUsage = ClaudeUsage()
...
# ----- 格式转换 -----
def _claude_messages_to_openai(
messages: list[ClaudeMessage],
system: str | list[dict] | None = None,
) -> list[dict]:
"""将 Claude 格式的 messages + system 转为 OpenAI 格式的 messages。"""
result: list[dict] = []
# system 提升为首条 system message
if system:
if isinstance(system, str):
result.append({"role": "system", "content": system})
elif isinstance(system, list):
# Claude 的 system 可以是 content blocks
text_parts = [b.get("text", "") for b in system if b.get("type") == "text"]
if text_parts:
result.append({"role": "system", "content": "\n".join(text_parts)})
for m in messages:
role = m.role
# content 为纯字符串
if isinstance(m.content, str):
if role == "user":
result.append({"role": "user", "content": m.content})
elif role == "assistant":
result.append({"role": "assistant", "content": m.content})
continue
# content 为 block 列表
if role == "user":
# 合并 text blocks;tool_result 转为 OpenAI tool message
text_parts: list[str] = []
for block in m.content:
if block.type == "text":
text_parts.append(block.text or"")
elif block.type == "tool_result":
# 先 flush 累积的 text
if text_parts:
result.append({"role": "user", "content": "\n".join(text_parts)})
text_parts = []
tool_content = block.content
if isinstance(tool_content, list):
tool_content = "\n".join(
b.get("text", "") if isinstance(b, dict) else str(b)
for b in tool_content
)
elifnot isinstance(tool_content, str):
tool_content = json.dumps(tool_content, ensure_ascii=False) if tool_content else""
result.append({
"role": "tool",
"tool_call_id": block.tool_use_id or"",
"content": tool_content,
})
if text_parts:
result.append({"role": "user", "content": "\n".join(text_parts)})
elif role == "assistant":
# 提取 text + tool_use
text_parts = []
tool_calls: list[dict] = []
for block in m.content:
if block.type == "text":
text_parts.append(block.text or"")
elif block.type == "tool_use":
tool_calls.append({
"id": block.id orf"call_{uuid.uuid4().hex[:8]}",
"type": "function",
"function": {
"name": block.name or"",
"arguments": json.dumps(block.input, ensure_ascii=False) if isinstance(block.input, dict) else str(block.input or"{}"),
},
})
msg: dict = {"role": "assistant", "content": "\n".join(text_parts) orNone}
if tool_calls:
msg["tool_calls"] = tool_calls
result.append(msg)
return result
def _claude_tools_to_openai(tools: list[ClaudeToolDef] | None) -> list[dict] | None:
"""将 Claude tools(input_schema)转为 OpenAI tools(parameters)。"""
ifnot tools:
returnNone
return [
{
"type": "function",
"function": {
"name": t.name,
"description": t.description or"",
"parameters": (
t.input_schema.model_dump(exclude_none=True)
if isinstance(t.input_schema, ClaudeToolInputSchema)
else t.input_schema or {"type": "object"}
),
},
}
for t in tools
]
def _claude_tool_choice_to_openai(tool_choice: dict | None) -> str | dict | None:
"""将 Claude tool_choice 转为 OpenAI tool_choice。"""
ifnot tool_choice:
returnNone
tc_type = tool_choice.get("type", "auto")
if tc_type == "auto":
return"auto"
if tc_type == "any":
return"required"
if tc_type == "tool":
return {"type": "function", "function": {"name": tool_choice.get("name", "")}}
if tc_type == "none":
return"none"
return"auto"
def _openai_finish_reason_to_claude(finish_reason: str) -> str:
"""将 OpenAI finish_reason 映射为 Claude stop_reason。"""
mapping = {
"stop": "end_turn",
"length": "max_tokens",
"tool_calls": "tool_use",
"content_filter": "end_turn",
}
return mapping.get(finish_reason, "end_turn")
# ----- 接口 -----
asyncdef _claude_stream_generator(req: ClaudeMessagesRequest):
"""Anthropic SSE 流式生成器 --- 遵循 Anthropic streaming events 协议。
事件序列:
message_start → content_block_start → content_block_delta* → content_block_stop
→ ... (更多 block) → message_delta → message_stop
"""
provider = _get_provider()
model = T_OPENAI_MODEL
messages = _claude_messages_to_openai(req.messages, req.system)
tools = _claude_tools_to_openai(req.tools)
tool_choice = _claude_tool_choice_to_openai(req.tool_choice)
msg_id = f"msg_{uuid.uuid4().hex[:24]}"
kwargs: dict[str, Any] = {
"model": model,
"messages": provider._sanitize_empty_content(messages),
"max_tokens": max(1, req.max_tokens),
"temperature": req.temperature or0.7,
"stream": True,
}
if tools:
kwargs["tools"] = tools
kwargs["tool_choice"] = tool_choice if tool_choice isnotNoneelse"auto"
def _sse(event: str, data: dict) -> str:
returnf"event: {event}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
try:
# message_start
yield _sse("message_start", {
"type": "message_start",
"message": {
"id": msg_id,
"type": "message",
"role": "assistant",
"content": [],
"model": req.model or model,
"stop_reason": None,
"stop_sequence": None,
"usage": {"input_tokens": 0, "output_tokens": 0},
},
})
# 跟踪当前 content block 状态
block_index = 0
block_open = False# 是否已经 open 了一个 text block
has_tool_call_blocks: list[dict] = [] # 已开启的 tool_use blocks
tool_args_buffers: dict[int, str] = {} # 缓存各 tool_call 的 arguments 片段
stream = await provider._client.chat.completions.create(**kwargs)
finish_reason = "stop"
asyncfor chunk in stream:
ifnot chunk.choices:
continue
delta = chunk.choices[0].delta
chunk_finish = chunk.choices[0].finish_reason
if chunk_finish:
finish_reason = chunk_finish
# ── 文本 delta ──
if delta.content isnotNoneand delta.content != "":
ifnot block_open:
yield _sse("content_block_start", {
"type": "content_block_start",
"index": block_index,
"content_block": {"type": "text", "text": ""},
})
block_open = True
yield _sse("content_block_delta", {
"type": "content_block_delta",
"index": block_index,
"delta": {"type": "text_delta", "text": delta.content},
})
# ── tool_calls delta ──
if delta.tool_calls:
# 先关闭 text block
if block_open:
yield _sse("content_block_stop", {
"type": "content_block_stop",
"index": block_index,
})
block_index += 1
block_open = False
for tc in delta.tool_calls:
tc_idx = tc.index
if tc_idx notin tool_args_buffers:
# 新 tool_use block
tool_args_buffers[tc_idx] = ""
tool_id = tc.id orf"toolu_{uuid.uuid4().hex[:12]}"
tool_name = tc.function.name if tc.function and tc.function.name else""
yield _sse("content_block_start", {
"type": "content_block_start",
"index": block_index + tc_idx,
"content_block": {
"type": "tool_use",
"id": tool_id,
"name": tool_name,
"input": {},
},
})
has_tool_call_blocks.append({"index": block_index + tc_idx, "id": tool_id, "name": tool_name})
# 累积 arguments
if tc.function and tc.function.arguments:
tool_args_buffers[tc_idx] += tc.function.arguments
yield _sse("content_block_delta", {
"type": "content_block_delta",
"index": block_index + tc_idx,
"delta": {
"type": "input_json_delta",
"partial_json": tc.function.arguments,
},
})
# ── 关闭所有未关闭的 blocks ──
if block_open:
yield _sse("content_block_stop", {
"type": "content_block_stop",
"index": block_index,
})
for tb in has_tool_call_blocks:
yield _sse("content_block_stop", {
"type": "content_block_stop",
"index": tb["index"],
})
# message_delta + message_stop
stop_reason = _openai_finish_reason_to_claude(finish_reason)
if has_tool_call_blocks:
stop_reason = "tool_use"
yield _sse("message_delta", {
"type": "message_delta",
"delta": {"stop_reason": stop_reason, "stop_sequence": None},
"usage": {"output_tokens": 0},
})
yield _sse("message_stop", {"type": "message_stop"})
except Exception as e:
logger.error(f"Claude 流式输出异常: {e}", exc_info=True)
yield _sse("error", {
"type": "error",
"error": {"type": "api_error", "message": f"AI 处理失败: {str(e)}"},
})
@router.post("/messages")
asyncdef claude_messages(req: ClaudeMessagesRequest):
"""Anthropic Claude 兼容的 Messages 接口
接收 Claude /v1/messages 格式的请求,内部转换为 OpenAI 格式调用 Provider,
再将响应转换回 Claude Messages 格式返回。
支持 stream=true 的 SSE 流式输出。
"""
ifnot req.messages:
raise HTTPException(status_code=400, detail={
"type": "invalid_request_error",
"message": "messages 不能为空",
})
# ── 流式输出 ──
if req.stream:
return StreamingResponse(
_claude_stream_generator(req),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
},
)
# ── 非流式输出 ──
try:
provider = _get_provider()
model = T_OPENAI_MODEL
# 转换请求格式:Claude → OpenAI
messages = _claude_messages_to_openai(req.messages, req.system)
tools = _claude_tools_to_openai(req.tools)
tool_choice = _claude_tool_choice_to_openai(req.tool_choice)
response = await provider.chat(
messages=messages,
model=model,
max_tokens=req.max_tokens,
temperature=req.temperature or0.7,
tools=tools,
tool_choice=tool_choice,
)
logger.info(f"Claude Messages 接口请求: model={req.model}, messages_count={len(req.messages)}")
logger.info(f"Claude Messages 接口响应: finish_reason={response.finish_reason}")
if response.finish_reason == "error":
raise HTTPException(status_code=502, detail={
"type": "api_error",
"message": response.content or"AI 服务返回错误",
})
# 构建 Claude 格式响应 content blocks
content_blocks: list[dict] = []
# 文本内容
if response.content:
content_blocks.append({"type": "text", "text": response.content})
# tool_use blocks
if response.tool_calls:
for tc in response.tool_calls:
content_blocks.append({
"type": "tool_use",
"id": tc.id,
"name": tc.name,
"input": tc.arguments if isinstance(tc.arguments, dict) else {},
})
# 如果既没有文本也没有 tool_use,补一个空 text block
ifnot content_blocks:
content_blocks.append({"type": "text", "text": ""})
# 确定 stop_reason
stop_reason = _openai_finish_reason_to_claude(response.finish_reason or"stop")
# 如果有 tool_calls 则 stop_reason 应为 tool_use
if response.tool_calls:
stop_reason = "tool_use"
usage_data = response.usage if response.usage else {}
return ClaudeMessagesResponse(
model=req.model or model,
content=content_blocks,
stop_reason=stop_reason,
usage=ClaudeUsage(
input_tokens=usage_data.get("prompt_tokens", 0) if isinstance(usage_data, dict) else0,
output_tokens=usage_data.get("completion_tokens", 0) if isinstance(usage_data, dict) else0,
),
)
except HTTPException:
raise
except RuntimeError as e:
raise HTTPException(status_code=500, detail={
"type": "api_error",
"message": str(e),
})
except Exception as e:
logger.error(f"Claude Messages 接口异常: {e}", exc_info=True)
raise HTTPException(status_code=500, detail={
"type": "api_error",
"message": f"AI 处理失败: {str(e)}",
})