找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5177

积分

0

好友

674

主题
发表于 1 小时前 | 查看: 4| 回复: 0

讲良心话,GPT-5.5 和 Opus 4.7 的模型能力已经非常强了。

哪怕是国产模型,配上顶级的 Harness 工具 Claude Code,也能变得异常强大。

下图是我最近肝出来的一个 PaiCLI 工具,交互体验和 Qoder CLI/Claude Code 很接近了。

终端界面截图,展示PaiCLI CLI工具的启动信息及对“沉默王二”身份的联网搜索过程

要知道,这可是完全通过 Java 实现的。

今天这篇内容,将会带大家从底层了解 Claude Code 的完整工作原理,并结合 PaiCLI 的源码,彻底讲清楚这些内容:

  • AI 编程工具的底层架构是什么?
  • 系统提示词应该怎么写?
  • Agent 的 ReAct 机制是什么?
  • Tool Use 和 Function Calling 之间有什么联系?
  • Multi-Agent 的机制是什么?
  • Memory 的机制是什么?
  • 上下文的压缩机制是什么?
  • CLAUDE.md 又是怎么让 Agent 快速掌握项目的?

非常硬核,系好安全带,我们粗粗粗粗发😄~

01、AI 编程工具的底层架构是什么?

答案是:大模型 + Harness

大模型负责“想”,Harness 负责“做”。大模型输出文本和工具调用指令,Harness 工具负责解析这些指令、执行工具、把结果喂回去给大模型继续想。

LLM + Harness分层架构流程图,包含大模型层、编排层和工具层

在 PaiCLI 项目里,Agent 是 Harness 的核心,LlmClient 是大模型的抽象接口。

PaiCLI项目Agent.java源码截图,展示了run方法中的核心逻辑

其中 while 循环就是所有 AI 编程工具的灵魂。

不管是 Claude Code 还是 Codex,底层都是这么一个循环:调用大模型 → 判断是否需要工具 → 需要就执行工具 → 把结果塞回历史 → 再调用大模型。直到大模型觉得任务完成了,不再调用工具,循环才结束。

PaiCLI ReAct循环执行过程流程图,展示多轮迭代中Thought、Action、Observation的流转

大模型和 Harness 之间的通信,走的是一套严格的消息协议。

每条消息都带有角色标识:system(系统提示词)、user(用户输入)、assistant(模型回复)、tool(工具执行结果)。Harness 维护一个 conversationHistory 列表,每次调用大模型时,把整个列表作为上下文传进去。

这里有个细节:

tool 消息必须带一个 toolCallId,和前面 assistant 消息中某个工具调用的 id 一一对应。

02、系统提示词应该怎么写?

Claude Code 不是直接“把用户的输入直接丢给大模型”。

在用户输入到达大模型之前,Harness 会拼接一段系统提示词(System Prompt),告诉大模型“你是谁、你能干什么、你应该怎么干”。

PaiCLI 的 PromptAssembler 展示了系统提示词的分层组装逻辑:

PromptAssembler.java代码截图,展示了通过加载多个Markdown文件拼接系统Prompt的逻辑

一共 7 层。

第一层 base.md 定义身份和工具清单。里面定义 Agent 的角色:“你是 PaiCLI,一个面向代码库工作的智能编程 Agent”,然后列出 11 个可用工具及其使用策略。

光列出工具名字还不够,还得告诉大模型每个工具什么时候该用、什么时候不该用。比如 PaiCLI 的 base.md 里写了这么一条规则:代码库相关问题优先 search_code,不要走 web_search

第二层是性格设定。calm.md 让 Agent 保持冷静、专业的语气。

第三层是工作模式。普通对话用 agent.md,里面写“根据用户目标决定是否需要工具”;多 Agent 协作时 Planner 用 team-planner.md,里面写“把任务拆解成 JSON 格式的执行计划”;Worker 用 team-worker.md,里面写“专注执行分配给你的子任务”。

第四层是审批策略,分三档:auto(所有操作自动执行)、suggest(危险操作需要人工确认)、never(所有工具调用都要确认)。默认是 suggest

后面几层是动态注入的项目上下文、技能列表、上下文管理规则。

base.md文件内容截图,展示了AI Agent的Identity、Language、Tools等核心配置

03、Agent 的 ReAct 机制是什么?

ReAct 是目前主流 Agent 框架的核心范式,全称是 Reasoning + Acting。

ReAct Agent扩展架构图,展示了多Agent协作、安全治理、记忆与知识等核心扩展模块

传统的 LLM 调用是一问一答。

用户问一个问题,模型回一个答案。但 Agent 不是这样的,Agent 需要多步推理、多步操作,中间可能执行十几次工具调用才能完成一个任务。

ReAct 的核心思想:让大模型在每一步都先“想”(推理当前状态和下一步计划),再“做”(调用一个工具执行操作),然后根据工具返回的结果继续“想”下一步。

在 PaiCLI 的 Agent 中,ReAct 循环的关键代码是这段:

if (response.hasToolCalls()) {
    // 添加助手消息(包含推理内容 + 工具调用)
    conversationHistory.add(LlmClient.Message.assistant(
            response.reasoningContent(), response.content(), response.toolCalls()));
    // 执行工具
    List<ToolExecutionResult> toolResults = executeToolCalls(response.toolCalls(), iteration);
    // 工具结果塞回历史
    for (ToolExecutionResult toolResult : toolResults) {
        conversationHistory.add(LlmClient.Message.tool(toolResult.id(), toolResult.result()));
    }
    // 继续循环,让 LLM 根据工具结果继续思考
    continue;
}

reasoningContent 是模型的内部推理过程(类似 DeepSeek 的深度思考),content 是面向用户的输出。推理过程不会直接展示给用户,但会被记录下来供调试使用。

终端界面截图,展示AI通过多轮网络搜索推理并回答“沉默王二是谁”的过程

举个具体例子。

假设用户说“沉默王二是谁?会像母猪上树吗?”,Agent 的 ReAct 过程大概是这样:

第一轮:想——“先搜一下沉默王二是谁”。做——调用 WebSearch 联网搜索。

第二轮:想——“搜到了,再确认沉默王二这个博主的身份”。做——调用 WebSearch 继续联网搜索。

第三轮:想——“好了,真相大白!总结一下”。做——直接输出文本回复,不调用工具。循环结束。

整个过程中,大模型在每一步都基于当前历史消息(包括之前的推理、工具调用和工具结果)进行决策。

04、Tool Use 和 Function Calling 之间有什么联系?

从技术本质上来说,Function Calling(函数调用)是实现 Tool Use(工具使用)的技术手段和协议标准。

LLM工具使用信息图,解释了Tool Use、Function Calling、API调用、代码执行和RAG的关系

  • 开发者告诉 AI 有哪些工具可用。使用 Function Calling 格式(通常是 JSON Schema)来定义函数名、描述和参数。
  • 模型根据用户问题判断是否需要工具,这是 Tool Use 的推理过程。
  • 模型触发 Function Calling,输出一段结构化的代码(例如 {"function": "get_weather", "params": {"city": "Shanghai"}})。
  • Agent 工具执行该代码,并将结果传回模型。模型最后整合信息,完成 Tool Use 的闭环。

我们在调用大模型 API 时,除了传入消息列表,还会传一个 tools 参数,里面定义了所有可用工具的名称、描述和参数 schema。大模型需要调用工具时,就会在回复中返回一个特殊结构,包含工具名称和参数 JSON。

PaiCLI 的 ToolRegistry 管理着所有工具的注册和执行。看这个 Tool 的定义:

ToolRegistry.java代码截图,展示了工具注册、配置参数和审计工具集合的定义

一个工具就是:名字 + 描述 + 参数定义 + 执行函数。

当 LLM 返回工具调用时,Harness 做三件事。

  • 第一,从返回中解析出工具名和参数。
  • 第二,在注册表中找到对应的 ToolExecutor。
  • 第三,执行并把结果包装成 tool message 塞回对话历史。

当 LLM 在一轮中返回多个工具调用时(比如同时要读三个文件),PaiCLI会开线程池并行跑:

ToolRegistry.java中executeTools方法源码,展示了并行执行多个工具调用的逻辑

Claude Code 也是这么做的。当模型判断多个工具调用之间没有依赖关系时,会在同一轮返回多个 tool_call,然后并行执行它们。

还有一个关键的扩展机制:MCP

MCP架构类层次关系图,展示了McpServerManager及各组件间的协作与继承关系

内置的工具毕竟有限,read_file、write_file、execute_command 能覆盖大部分编程场景,但如果要操作浏览器、连接数据库、调用企业内部 API 怎么办?

MCP 的做法是把工具的“注册权”开放出去。

任何外部服务只要实现 MCP 协议,就能把自己的工具动态注册到 Agent 的工具列表中。PaiCLI 里这些工具的命名规则是 mcp__{服务名}__{工具名},比如 mcp__chrome-devtools__take_screenshot 就是浏览器截图工具。

Agent 压根不知道这些工具的内部实现,它只能看到名称、描述和参数 schema。

大模型根据描述判断什么时候调用,Harness 负责把调用转发给对应的 MCP 服务器。这种设计让 Agent 的能力可以无限扩展。

05、Multi-Agent 的机制是什么?

核心机制可以概括为:将复杂任务拆解,由多个具备不同“人设”和“工具”的 Agent 协作完成。

  • 不再让一个模型处理所有事,而是通过 System Prompt 为不同的智能体赋予特定身份。
  • 常见的协作模式Planner-Worker-Reviewer,由规划者调度,给各个执行者派活。

多智能体系统架构图,包含UML类图和Planner-Worker-Reviewer协作工作流

Planner(规划者) 负责把用户的大任务拆解成多个小步骤,生成一个 JSON 格式的执行计划,包含每个步骤的描述和依赖关系。

Worker(执行者) 负责执行具体的小任务。每个 Worker 都是一个独立的 SubAgent,有自己的对话历史和系统提示词,互不干扰。多个 Worker 可以并行工作。

Reviewer(审查者) 负责检查 Worker 的输出质量。如果不合格,会给出反馈让 Worker 重新执行(最多重试 2 次)。

为什么需要 Multi-Agent?

第一,突破上下文限制,各司其职,每个 Agent 只处理自己那一小块最相关的上下文。

第二,模型很难发现自己的逻辑错误,但“旁观者清”,让 Agent B 去审计 Agent A 的输出,能极大提升可靠性。

第三,多模型组合。比如说让 Opus 4.7 规划,GPT-5.5 去执行。

这里有一个关键的设计细节:上下文隔离。每个 Worker 启动时会创建独立的对话历史,只注入和自己任务相关的上下文,执行完毕后只把结果摘要(而不是完整对话)返回给 Orchestrator。这样做的好处是,Worker A 读了 50 个文件产生的上下文不会污染 Worker B 的判断,各自的注意力都集中在自己的子任务上。

06、Memory 的机制是什么?

Memory 机制是让模型能够“记住”过去发生的事情,并将其作为当前决策参考的技术。

如果没有记忆机制,AI 每次对话都是“失忆”的。

Memory 机制 = 上下文管理 (Context) + 向量检索 (RAG) + 自动摘要 (Summarization)。

LLM记忆体系信息图,详细对比了短期记忆、长期记忆和上下文压缩的定位与实现

Agent 的 Memory 分两层:短期记忆长期记忆

短期记忆就是当前对话的上下文。

每次用户发消息、Agent 回复、工具执行结果,都会被追加到对话历史里。

长期记忆是跨会话持久的信息。

PaiCLI 的 LongTermMemory 把用户偏好、项目事实等关键信息存到 ~/.paicli/long_term_memory.json 文件中。每次新会话开始时,Agent 会根据当前输入检索相关的长期记忆,注入到系统提示词中。

// Agent.java 第 127 行
String memoryContext = memoryManager.buildContextForQuery(
    userInput, contextProfile.memoryContextTokens());
updateSystemPromptWithMemory(memoryContext);

长期记忆的难点在于“检索”。

比如说存了 100 条记忆,当前问题只跟其中 3 条相关,怎么精准找到这 3 条?

PaiCLI 用的是混合检索:BM25 关键词匹配 + 语义相似度。先用关键词快速过滤候选集,再用语义相似度排序,最终只注入排名靠前的几条。

记忆检索效果图,展示了相关性排序结果及评分公式的详细拆解

07、上下文的压缩机制是什么?

短期记忆满了,旧消息得淘汰,但关键信息不能丢。

怎么办?

压缩成摘要,再注入回去。

压缩策略用的是 Map-Reduce,跟处理大文档的思路一样:

Map-Reduce上下文压缩流程图,展示将消息分片摘要并合并的过程

压缩算法是这样的:

  1. 触发条件:当对话历史的 token 数达到上下文窗口的 90% 时触发压缩。
  2. 分割点选择:找到所有 user message 的位置,保留最近 3 轮用户对话不动,把之前的所有消息作为“待压缩区域”。
  3. 摘要生成:把待压缩区域的消息喂给 LLM,让它生成一段精简摘要。
  4. 重建历史[system] + [user("已压缩的历史对话摘要\n" + summary)] + [assistant("好的,已了解上下文。")] + [最近 3 轮完整对话]

08、CLAUDE.md 是怎么让 Agent 快速掌握项目的?

CLAUDE.md 让用户可以通过一个 markdown 文件告诉 Agent “这个项目的规则是什么”。

AGENTS.md文档截图,展示了项目快照、运行前提和常用命令等信息

它的工作原理其实很简单:在组装系统提示词时,把 CLAUDE.md 的内容注入进去。

PaiCLI 用的是 AGENTS.md,但原理一样。

PromptAssemblerdynamicSection("Project Context", ...) 这一步,把项目级别的规则和上下文拼接到系统提示词中。

PromptAssembler类assemble方法源码,展示了项目上下文注入的技术实现

CLAUDE.md 的写作有几个原则:

  • 明确具体,不要含糊。写“使用 4 空格缩进”比写“保持一致的代码风格”有用一百倍。
  • 控制长度。CLAUDE.md 会占用上下文窗口。写太长了,留给实际工作的空间就少了。PaiCLI 的设计中,项目上下文注入有严格的 token 预算:memoryContextTokens = min(5000, window/200)
  • 分层加载。Claude Code 支持全局 ~/.claude/rules/、项目级 .claude/settings.json、文件级 CLAUDE.md 三层规则。PaiCLI 也是类似的三层结构:内置 < 用户全局(~/.paicli/)< 项目级(.paicli/)。优先级从低到高,项目级的配置会覆盖全局配置。

面试真经

再来几道真实的面试题和口述版本的答案,可以直接背。

请介绍一个你参与的、与 AI Agent 相关的项目,并说明你的角色和贡献?

我独立开发了 PaiCLI,一个基于 Java 的 AI Agent CLI 工具,交互体验和 Claude Code 很接近。我是唯一的开发者,从架构设计到所有模块的实现都是我一个人完成的。

PaiCLI终端启动界面,展示Banner、模型信息和操作提示

底层架构是 LLM + Harness 模式,Agent 类作为 Harness 核心,驱动一个标准的 ReAct 循环:调用大模型 → 判断是否需要工具 → 执行工具 → 结果塞回对话历史 → 再调用大模型,直到任务完成。

Memory 机制方面,PaiCLI 实现了双层记忆系统。短期记忆是当前对话的消息列表,用 LinkedHashMap 做 FIFO 淘汰;长期记忆把用户偏好、项目事实等信息持久化到本地 JSON 文件中,每次新会话时根据当前输入做混合检索(BM25 关键词 + 语义相似度),把最相关的记忆注入系统提示词。

RAG 模块方面,PaiCLI 用 JavaParser 把代码按文件/类/方法三级切块,再通过 Ollama 或远程 API 向量化,存到 SQLite。检索时用混合打分——语义相似度 + 关键词匹配 + 代码块类型加权(方法级权重最高)+ 双命中奖励,防止单个大文件霸占结果。

Multi-Agent 协作方面,PaiCLI 实现了 Planner-Worker-Reviewer 三角色架构。AgentOrchestrator 负责协调,Planner 把大任务拆成 JSON 格式的执行计划,多个 Worker 根据依赖关系并行执行,Reviewer 检查输出质量、不合格就打回重做(最多 2 次)。只有 Worker 有工具调用权限,Planner 和 Reviewer 只输出纯 JSON,保持角色清晰。

CDP通信流程图,展示Chrome浏览器与外部程序通过WebSocket交互的机制

Chrome DevTools MCP 是 PaiCLI 的一个亮点。通过集成 chrome-devtools-mcp,Agent 能直接操控浏览器——截图、点击、填表、执行 JS。工具自动注册为 mcp__chrome-devtools__* 格式,大模型根据工具描述自主判断什么时候调用。

更有意思的是 CDP 登录态复用。默认情况下 Agent 启动的是隔离浏览器(独立 user-data-dir),碰到需要登录的页面就没辙了。PaiCLI 的做法是:Agent 检测到登录墙后,自动切换到共享模式(--autoConnect),通过 Chrome 的 DevToolsActivePort 文件发现用户正在运行的浏览器实例,直接复用已有的登录态。

谈一谈你对 ReAct 框架的理解?

ReAct 让推理和行动交替进行。

大模型在每一步会先输出推理过程(分析当前状态、规划下一步),再输出具体行动(工具调用)。工具返回结果后,大模型再推理下一步。

这个循环会持续到大模型判断任务完成。

ReAct流程图,展示从用户提问到Thought、Action、Observation的循环过程

ReAct 的退出有两种方式:

  • 一是 LLM 在某一轮不返回 tool_call,说明它认为任务已完成;
  • 二是 token 预算耗尽或检测到死循环,由 Harness 强制终止。

PaiCLI 的 AgentBudget 负责第二种退出,它追踪累计消耗的 input + output token,超过 maxContextWindow × 0.8 就终止。

在 AI Agent 中,记忆通常分为哪几种类型?

分短期记忆和长期记忆。短期记忆就是当前对话的消息列表,包含用户输入、Agent 回复和工具执行结果,会话结束就清空。长期记忆是跨会话持久化的信息,存储用户偏好、项目事实等稳定知识,每次新对话时根据相关性检索注入。

AI记忆管理系统架构图,展示短期记忆、长期记忆、上下文压缩与Token预算管理的协同关系

在开发 Agent 时,如何设计提示词来提升任务执行的稳定性和准确性?

三个层面。

PaiCLI项目prompts目录结构,展示了分层组织的Markdown提示词文件

第一是分层组装:把系统提示词拆成身份层、能力层、策略层、上下文层,每层独立维护、组合灵活。

第二是约束前置:把限制条件(安全策略、路径约束、禁止操作)写在提示词靠前的位置,因为大模型对前面的内容关注度更高。

第三是动态注入:根据当前任务类型、项目上下文、相关记忆动态调整提示词内容,而不是用一套固定的 prompt 应对所有场景。

实现一个简单的多轮对话状态管理,你会考虑哪些关键要素?

四个要素。

第一是消息格式规范:每条消息都要有明确的角色标识(system/user/assistant/tool),tool 消息必须带 tool_call_id 与前面的调用配对。

第二是上下文窗口管理:需要一个压缩/截断策略,当消息总 token 逼近窗口上限时自动压缩早期消息。

第三是状态一致性:tool_call 和 tool_result 必须成对出现,压缩分割点不能打断这种配对关系。

第四是取消机制:支持用户中途取消,Agent 的 while 循环在每次迭代前检查取消标记。

Agent工作流全景图,从用户提问到Prompt构建、ReAct引擎、Tool Use与记忆模块的完整闭环


如果你对 AI Agent 的底层原理和实战项目感兴趣,不妨来云栈社区与更多同好交流,这里有大量像 PaiCLI 一样“知其然更知其所以然”的技术中坚力量在等你一起探讨。




上一篇:系统越来越难改吗?错在架构失控,而非代码烂
下一篇:主流MQ选型实战:从场景对比到Kafka发送链路源码深度拆解
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-14 22:27 , Processed in 0.650246 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表