指南:基于 MCP 工具集的 SSE 流式 Agent 對(duì)話架構(gòu))
【免費(fèi)下載鏈接】repowiseCodebase intelligence for AI and humans: code health scores, auto-generated docs, git analytics, dead code detection, and architectural decisions via MCP.項(xiàng)目地址https://gitcode.com/gh_mirrors/re/repowise點(diǎn)擊查看免費(fèi)下載本文是 Repowise「代碼庫(kù)聊天Codebase Chat」功能的技術(shù)參考與實(shí)戰(zhàn)解析。該功能讓用戶以自然語(yǔ)言直接與代碼庫(kù)交互Agent 使用用戶配置的任意 LLM Provider從 MCP 工具面MCP surface精選7 個(gè)工具而非完整的 11 個(gè)默認(rèn) MCP 工具通過(guò) SSE 把流式響應(yīng)實(shí)時(shí)推送到瀏覽器邊生成邊展示工具調(diào)用過(guò)程并在 Artifact 面板中渲染工具結(jié)果。讀完本文你將掌握其端到端調(diào)用鏈數(shù)據(jù)庫(kù) → ChatProvider 協(xié)議 → Agentic Loop → SSE → 前端狀態(tài)機(jī)、Provider 配置解析規(guī)則、SSE 事件協(xié)議以及各 ProviderAnthropic / OpenAI / Gemini / Ollama / LiteLLM的差異化實(shí)現(xiàn)。文中所有實(shí)現(xiàn)細(xì)節(jié)均可在當(dāng)前倉(cāng)庫(kù)源碼中找到對(duì)應(yīng)依據(jù)。1. 架構(gòu)總覽一次提問(wèn)的完整旅程用戶在聊天框輸入問(wèn)題后請(qǐng)求按如下鏈路流轉(zhuǎn)流程圖引自 docs/architecture/chat.md并對(duì)照 聊天路由實(shí)現(xiàn) 做了細(xì)化User types question | v POST /api/repos/{repo_id}/chat/messages | v ------ Chat Router (SSE stream) ------ | | | 1. Create/load conversation | | 2. Save user message to DB | | 3. Build LLM message history | | 4. Call provider.stream_chat() -------- tool_executor callback | | | | v | | 5. Stream text_delta events ------- SSE to browser | 6. On tool_start: | | - Execute tool (or provider | | executes internally) | | - Emit tool_result event ------- SSE to browser | 7. If tool calls found: | | - Append to history, loop to 4 | | 8. If no tool calls: | | - Save assistant message to DB | | - Emit done event | ---------------------------------------一個(gè)關(guān)鍵設(shè)計(jì)決策是Agentic Loop 默認(rèn)跑在 Chat Router 中OpenAI、Anthropic、Ollama、LiteLLM 皆是如此只有 Gemini 例外——它的循環(huán)在stream_chat()內(nèi)部執(zhí)行。原因在于 Gemini 的 API 要求在回放對(duì)話歷史中的函數(shù)調(diào)用時(shí)攜帶thought_signature簽名而通過(guò) Router 做 OpenAI 格式的往返轉(zhuǎn)換會(huì)丟失該簽名因此 Router 向 Gemini 傳入一個(gè)tool_executor回調(diào)由 Gemini 在內(nèi)部循環(huán)中直接調(diào)用。這一點(diǎn)在第 10 節(jié)會(huì)詳細(xì)展開(kāi)。2. 數(shù)據(jù)庫(kù) Schema會(huì)話與消息的持久化兩張表由遷移0005_chat_conversations.py引入遷移文件位于 packages/core/alembic/versions/0005_chat_conversations.py其中upgrade()與文檔描述完全對(duì)應(yīng)。conversations表ColumnTypeNotesidString(32)PKUUID hexrepository_idString(32)FKrepositories.idondeleteCASCADEtitleText自動(dòng)生成新會(huì)話默認(rèn)New conversation首輪回答后由前 6 個(gè)詞提煉created_atDateTime(tz)server_defaultsa.func.now()updated_atDateTime(tz)收到新消息時(shí)自動(dòng)更新索引ix_conversations_repo_updated建立在(repository_id, updated_at)上——按倉(cāng)庫(kù)列出會(huì)話并按更新時(shí)間排序是主要查詢路徑。chat_messages表ColumnTypeNotesidString(32)PKUUID hexconversation_idString(32)FKconversations.idondeleteCASCADEroleString(32)user或assistantcontent_jsonTextJSON 負(fù)載見(jiàn)下created_atDateTime(tz)索引ix_chat_messages_conv_created建立在(conversation_id, created_at)上。消息內(nèi)容格式用戶消息{text: What does the auth module do?}助手消息除了正文文本還會(huì)把本輪所有工具調(diào)用及其結(jié)果作為持久化負(fù)載一起存儲(chǔ)tool_calls數(shù)組這樣歷史會(huì)話回放時(shí)能完整還原當(dāng)時(shí)的工具證據(jù){ text: The auth module handles..., tool_calls: [ { id: call_abc123, name: get_context, arguments: {targets: [src/auth]}, result: { ... } } ] }從源碼看存儲(chǔ)的tool_calls條目實(shí)際結(jié)構(gòu)為{id, name, arguments, summary, artifact}即還包含工具結(jié)果摘要與 Artifact 信封見(jiàn) routers/chat.py 中_stored_tool_callArtifact 數(shù)據(jù)隨消息持久化歷史會(huì)話無(wú)需重新調(diào)用工具即可回放結(jié)果面板。3. ChatProvider 協(xié)議可選接入的流式聊天能力協(xié)議定義在 packages/core/src/repowise/core/providers/llm/base.py。設(shè)計(jì)要點(diǎn)既有的BaseProvider.generate()完全不動(dòng)新增一個(gè)基于typing.Protocolruntime_checkable的ChatProvider協(xié)議類把「流式聊天 工具調(diào)用」作為 Provider 的可選能力——實(shí)現(xiàn)stream_chat()即視為支持。runtime_checkable class ChatProvider(Protocol): def stream_chat( self, messages: list[dict], # OpenAI-format message list tools: list[dict], # OpenAI-format tool definitions system_prompt: str, max_tokens: int 8192, temperature: float 0.7, request_id: str | None None, tool_executor: Any | None None, # async callable(name, args) - dict ) - AsyncIterator[ChatStreamEvent]: ...配套數(shù)據(jù)類ChatToolCall(id, name, arguments)— LLM 想執(zhí)行的工具調(diào)用ChatStreamEvent(type, text?, tool_call?, tool_result_data?, stop_reason?, input_tokens, output_tokens)— 流中的一個(gè)事件。事件類型type填充字段含義text_deltatext增量文本 tokentool_starttool_callLLM 請(qǐng)求調(diào)用某個(gè)工具tool_resulttool_call,tool_result_data工具已執(zhí)行由 Provider 內(nèi)部執(zhí)行時(shí)usageinput_tokens,output_tokenstoken 用量更新stopstop_reason生成結(jié)束end_turn/tool_use/max_tokens消息統(tǒng)一使用OpenAI 格式的 dict 列表作為協(xié)議輸入各 Provider 在stream_chat()內(nèi)部自行轉(zhuǎn)換為自家原生格式。stop_reason采用 Provider 無(wú)關(guān)的中性取值base.py中的normalize_stop_reason()會(huì)把各廠商枚舉stop、length、tool_calls、function_call等歸一化為end_turn、max_tokens、tool_use未知值原樣保留以便診斷?,F(xiàn)有實(shí)現(xiàn)Anthropic、OpenAI、Gemini、Ollama、LiteLLM。它們都接受tool_executor參數(shù)但只有 Gemini 真正使用它用于thought_signature處理見(jiàn)第 10 節(jié)。4. Tool Registry聊天工具的唯一事實(shí)來(lái)源定義在 packages/server/src/repowise/server/chat_tools.py。它是聊天工具 schema 與執(zhí)行的單一來(lái)源從 MCP 注冊(cè)表投影出「請(qǐng)求作用域」的工具面向 LLM 暴露 OpenAI 格式的 function 定義。核心函數(shù)函數(shù)用途get_tool_catalog(repo_path)返回該倉(cāng)庫(kù)配置的 MCP 工具面含生成的 schemaget_tool_schemas_for_llm()轉(zhuǎn)成 OpenAI 格式的 tool definitions 交給 LLMexecute_tool(name, args)僅當(dāng)工具屬于該倉(cāng)庫(kù)配置面時(shí)執(zhí)行并保證輸出可 JSON 序列化get_artifact_type(name)/get_artifact_presentation(name)/get_artifact_evidence_basis(name)把工具名映射為前端 Artifact 類型 / 呈現(xiàn)方式 / 證據(jù)依據(jù)init_tool_state(...)把 FastAPI app state 橋接到 MCP 模塊全局session 工廠、FTS、向量庫(kù)、決策存儲(chǔ)、repo 路徑實(shí)現(xiàn)細(xì)節(jié)值得注意工具面由倉(cāng)庫(kù)配置決定get_tool_catalog調(diào)用selected_tool_entries(repo_path)即工具集來(lái)自倉(cāng)庫(kù)的 MCP 配置而非寫(xiě)死的列表雙重安全約束execute_entry遵循ToolEntry.safety合約——mutating工具在未顯式確認(rèn)時(shí)直接返回confirmation_required錯(cuò)誤執(zhí)行失敗不會(huì)拋異常中斷流而是返回{error: ..., error_code: tool_failed}工作區(qū)別名兜底_scope_repo_arg會(huì)攔截模型擅自填寫(xiě)的repo參數(shù)用當(dāng)前工作區(qū)別名覆蓋確定性序列化_make_json_serializable遞歸把 dict/list/dataclass 轉(zhuǎn)成純 JSON 類型避免 SSE 序列化失敗。7 個(gè)聊天工具與 Artifact 類型映射聊天 Agent 只暴露精選子集不包含完整的 MCP 默認(rèn)面沒(méi)有g(shù)et_answer、get_symbol、get_health、list_reposToolArtifact Typeget_overviewoverviewget_contextwiki_pageget_riskrisk_reportget_change_riskrisk_reportget_whydecisionssearch_codebasesearch_resultsget_dead_codedead_code前端 ArtifactPanel 依據(jù)artifact.type決定渲染方式Markdown、Mermaid 圖、搜索結(jié)果、原始 JSON。5. Provider 配置API Key 與活動(dòng) Provider 的解析鏈實(shí)現(xiàn)在 packages/server/src/repowise/server/provider_config.py。API Key 與活動(dòng) Provider/模型選擇存儲(chǔ)在服務(wù)端provider_config.json中路徑為$REPOWISE_CONFIG_DIR/provider_config.json未設(shè)置時(shí)位于~/.repowise/provider_config.json環(huán)境變量?jī)?yōu)先于存儲(chǔ)的 Key。文件采用「先寫(xiě)臨時(shí)文件再os.replace原子替換」的方式落盤(pán)并盡力設(shè)置0600權(quán)限保護(hù) Key 材料日志輸出會(huì)用_redact_key對(duì)sk-前綴的 Key 打碼。API Key 解析順序源碼為三層比文檔更細(xì)進(jìn)程環(huán)境變量如GEMINI_API_KEY、ANTHROPIC_API_KEY、OPENAI_API_KEY目標(biāo)倉(cāng)庫(kù)的.repowise/.env——以 dict 形式讀取不會(huì)注入os.environ因此工作區(qū)模式下某個(gè)倉(cāng)庫(kù)的 Key 不會(huì)泄漏到另一個(gè)倉(cāng)庫(kù)服務(wù)端存儲(chǔ)的 Keyprovider_config.json中keys段通過(guò)set_api_key寫(xiě)入。另外UI 里新增的 Key 會(huì)被_mirror_key_to_repo_env同步鏡像到該倉(cāng)庫(kù)的.repowise/.env以 Provider 目錄中的第一個(gè)規(guī)范環(huán)境變量名為準(zhǔn)這樣之后在該倉(cāng)庫(kù)跑 CLI 也能讀到同一把 Key——CLI 只讀.env不讀服務(wù)端存儲(chǔ)?;顒?dòng) Provider 解析順序源碼為五層覆蓋文檔的兩步每倉(cāng)庫(kù)持久化的 UI 選擇provider_config.json的repos[repo_id]——這是用戶對(duì)該倉(cāng)庫(kù)的顯式覆蓋按倉(cāng)庫(kù)隔離避免「為一個(gè)倉(cāng)庫(kù)選模型卻影響其他倉(cāng)庫(kù)」的歷史 bug倉(cāng)庫(kù)自身config.yamlprovidermodel由repowise init寫(xiě)入——無(wú)縫默認(rèn)服務(wù)端全局active_providerPATCH /api/providers/active寫(xiě)入的舊式單倉(cāng)庫(kù)狀態(tài)REPOWISE_PROVIDER/REPOWISE_MODEL環(huán)境變量自動(dòng)探測(cè)——遍歷目錄取第一個(gè)有可用 Key 或無(wú)需 Key 的 Provider。Provider 目錄文檔第 5 節(jié)列出的核心目錄為 Gemini、Anthropic、OpenAI、Ollama本地、無(wú)需 Key、LiteLLM對(duì)照當(dāng)前源碼中的PROVIDER_CATALOG實(shí)際還包含 OpenRouter、DeepSeek、Kimi、Eden AI、Claude Code本地 CLI、Codex本地 CLI、OpenCode本地 CLI等。每個(gè)條目聲明default_model、可選的models列表、env_keys與requires_key。示例源碼原文{ id: gemini, name: Google Gemini, default_model: gemini-3.5-flash-lite, models: [gemini-3.5-flash-lite, gemini-3.1-flash-lite, gemini-3.1-pro-preview], env_keys: [GEMINI_API_KEY, GOOGLE_API_KEY], requires_key: True, },base_url同樣有三層解析進(jìn)程環(huán)境變量名目來(lái)自PROVIDER_BASE_URL_ENVS與 CLI/MCP 解析共用同一張表保證不漂移→ 倉(cāng)庫(kù).env→ 倉(cāng)庫(kù)config.yaml中按 Provider 分段的openai: {base_url: http://localhost:4000/v1}這類寫(xiě)法。這使得本地 LiteLLM / OpenAI 兼容端點(diǎn)可以在init時(shí)配置并被聊天復(fù)用。6. SSE 流式協(xié)議瀏覽器實(shí)時(shí)看到生成過(guò)程聊天端點(diǎn)返回Content-Type: text/event-stream。每個(gè)事件格式event: data data: {type: ..., ...}事件形狀逐條解析// LLM 的增量文本 {type: text_delta, text: The auth module...} // LLM 要調(diào)用工具 {type: tool_start, tool_id: call_123, tool_name: get_context, input: {targets: [src/auth]}} // 工具執(zhí)行完成 {type: tool_result, tool_id: call_123, tool_name: get_context, summary: Context for 1 target(s), artifact: {type: wiki_page, data: {...}}} // 流結(jié)束 {type: done, conversation_id: abc123, message_id: def456} // 錯(cuò)誤 {type: error, message: Provider error: ...}HeadersCache-Control: no-cache, no-transform、X-Accel-Buffering: no、Connection: keep-alive。其中no-transform是為了防止 Next.js rewrite 代理的壓縮中間件對(duì)流做 gzip 緩沖與 jobs 流同一處理策略。Retry流開(kāi)始時(shí)發(fā)送retry: 3000。終端事件紀(jì)律每條流必須以done或error在data通道上收尾。前端useChat只按type字段分派事件因此發(fā)送到其他通道、或缺少type的事件會(huì)被丟棄——客戶端只會(huì)看到「回答到一半流停了」??蛻舳嗽?reader 結(jié)束時(shí)若未收到終端事件會(huì)自行結(jié)算本地狀態(tài)把進(jìn)行中的工具標(biāo)為錯(cuò)誤態(tài)但服務(wù)端仍然欠它一個(gè)終端事件。源碼中該格式由_sse_event(event, data)統(tǒng)一生成見(jiàn) routers/chat.py。此外源碼還會(huì)在特定場(chǎng)景發(fā)出文檔未列出的補(bǔ)充事件{type: suggestions, suggestions: [...]}—— 回答完成、且本輪有可跟進(jìn)問(wèn)題時(shí)附帶建議追問(wèn){type: truncated, loops: 10}—— 10 輪循環(huán)全部以工具調(diào)用結(jié)束、始終未產(chǎn)出最終答案時(shí)發(fā)出。7. Agentic Loop最多 10 輪的模型-工具交替循環(huán)循環(huán)每請(qǐng)求最多運(yùn)行10 次迭代源碼常量_MAX_AGENTIC_LOOPS 10見(jiàn) routers/chat.pyfor each iteration: 1. Call provider.stream_chat(messages, tools, system_prompt, tool_executor) 2. Collect text_delta events - stream to client 3. Collect tool_start events - stream to client 4. Collect tool_result events (from internal execution) - stream to client 5. If there are pending tool calls (not internally executed): a. Execute each tool b. Emit tool_result to client c. Append assistant tool results to message history d. Continue loop 6. If no tool calls: break循環(huán)結(jié)束后助手消息文本 全部工具調(diào)用及其結(jié)果保存到數(shù)據(jù)庫(kù)并發(fā)出done事件。對(duì)照源碼_AgentTurn的實(shí)現(xiàn)有幾個(gè)值得說(shuō)明的細(xì)節(jié)兩階段工具執(zhí)行模型_model_turn收集tool_start事件進(jìn)入pending列表若 Provider 已內(nèi)部執(zhí)行tool_result事件則從pending中移除對(duì)應(yīng)項(xiàng)——這正是 Gemini 內(nèi)部循環(huán)與 Router 循環(huán)的協(xié)作點(diǎn)客戶端斷連即中止每輪都檢查request.is_disconnected()斷連置aborted并停止不保存任何內(nèi)容源碼注釋明確客戶端斷連或 Provider 失敗時(shí)不落庫(kù)避免半截回答污染歷史grounding 預(yù)讀在模型第一輪之前Router 會(huì)基于頁(yè)面上下文ChatPageContext用plan_groundingrun_grounding做一次「該頁(yè)面已獲授權(quán)的讀取」例如打開(kāi) Wiki 頁(yè)先拉一次get_context并把結(jié)果注入消息歷史、以origingrounding標(biāo)記存儲(chǔ)重復(fù)的調(diào)用會(huì)被歷史去重跳過(guò)ProviderError 即 error 事件模型調(diào)用拋出ProviderError時(shí)置aborted并立即yield一個(gè)errorSSE 事件截?cái)鄻?biāo)記10 輪全是工具調(diào)用時(shí)置truncatedTrue回復(fù)內(nèi)容中帶truncated標(biāo)記并發(fā)出truncated事件。歷史構(gòu)建方面_db_messages_to_llm_format把數(shù)據(jù)庫(kù)消息轉(zhuǎn)成 LLM 格式_with_navigation_context再注入頁(yè)面導(dǎo)航上下文工具結(jié)果以tool_result_message回填歷史助手側(cè)用assistant_tool_call_message記錄本輪文本與工具調(diào)用。8. REST API 端點(diǎn)Chat 端點(diǎn)MethodPathDescriptionPOST/api/repos/{repo_id}/chat/messagesSSE 流——發(fā)送消息并獲取流式響應(yīng)GET/api/repos/{repo_id}/chat/conversations列出倉(cāng)庫(kù)的會(huì)話GET/api/repos/{repo_id}/chat/conversations/{id}獲取會(huì)話及其全部消息DELETE/api/repos/{repo_id}/chat/conversations/{id}刪除會(huì)話POST body{ message: What does the auth module do?, conversation_id: null, provider: null, model: null }conversation_id— 省略或null表示開(kāi)啟新會(huì)話provider/model— 可選的單請(qǐng)求覆蓋即 UI 的模型選擇器僅對(duì)本次請(qǐng)求生效不帶覆蓋時(shí)按第 5 節(jié)的倉(cāng)庫(kù)級(jí)解析鏈確定 Provider 與模型。從源碼看POST還接受一個(gè)context字段kind/label/target/target_kind用于把頁(yè)面上下文傳給 grounding 與系統(tǒng)提示詞且所有聊天端點(diǎn)都受verify_api_key依賴保護(hù)Router 級(jí)依賴。補(bǔ)充端點(diǎn)源碼中的完整面超出文檔表格源碼中的聊天路由還提供了會(huì)話生命周期管理的更多端點(diǎn)均帶verify_api_key依賴GET /api/repos/{repo_id}/chat/suggestions?kind...target...— 基于頁(yè)面已獲授權(quán)讀取生成建議問(wèn)題不產(chǎn)生模型調(diào)用與主聊天共用同一套 grounding 函數(shù)保證兩處對(duì)頁(yè)面類型的映射永不漂移POST /api/repos/{repo_id}/chat/conversations/{id}/restore— 恢復(fù)軟刪除的會(huì)話PATCH /api/repos/{repo_id}/chat/conversations/{id}— 更新標(biāo)題或固定pinned狀態(tài)標(biāo)題不可為空POST /api/repos/{repo_id}/chat/conversations/{id}/fork— 從某個(gè)消息節(jié)點(diǎn)派生新會(huì)話through_message_id與before_message_id二選一GET /api/repos/{repo_id}/chat/conversations/{id}/artifacts/{artifact_id}與PATCH .../artifacts/{artifact_id}— 讀取歷史消息中持久化的 Artifact、切換其固定狀態(tài)。Providers 端點(diǎn)MethodPathDescriptionGET/api/providers列出全部 Provider 及其狀態(tài)與活動(dòng)選擇PATCH/api/providers/active設(shè)置活動(dòng) Provider 與模型POST/api/providers/{id}/key存儲(chǔ) API KeyDELETE/api/providers/{id}/key移除 API Key9. 前端架構(gòu)API 層packages/api-client/src/chat.ts—listConversations、getConversation、deleteConversation、getChatSuggestions、restoreConversation、updateConversation、forkConversation、getConversationArtifact、setConversationArtifactPinned核心的postChatMessage返回原始Response而非解析后的 JSON供調(diào)用方讀取response.body作為ReadableStream逐幀消費(fèi) SSE。它還會(huì)透?jìng)鰽bortSignal不僅中止讀循環(huán)連 POST 請(qǐng)求本身一起中止否則服務(wù)端 Agentic Loop 會(huì)繼續(xù)空轉(zhuǎn)、DB 會(huì)話直到 socket 坍塌才被回收Provider 管理封裝getProviders/setActiveProvider/addProviderKey/removeProviderKey同樣在 api-client 層。HooksuseChat(repoId)實(shí)現(xiàn)見(jiàn) packages/web/src/lib/hooks/use-chat.ts—— 完整的聊天狀態(tài)機(jī)。使用fetchReadableStream讀取而非EventSource后者僅支持 GET。管理消息列表、流式狀態(tài)、會(huì)話 ID、錯(cuò)誤處理與中止控制。實(shí)現(xiàn)上的細(xì)節(jié)用AbortController在中止/切換倉(cāng)庫(kù)/組件卸載時(shí)打斷流文本增量通過(guò)requestAnimationFrame批處理queueText/flushText避免高頻 text_delta 觸發(fā)過(guò)量 React 重渲染流異常終止時(shí)用stopRunningTools把進(jìn)行中的工具調(diào)用標(biāo)記為錯(cuò)誤態(tài)并附上說(shuō)明。對(duì)外暴露sendMessage、loadConversation、resetuseProviders()—— SWR 包裝的 Provider 管理暴露providers、activeProvider、activeModel、activate、saveKey、removeKey。組件packages/ui/src/chat/與packages/web/src/components/chat/組件用途ChatInterface主容器——空態(tài)問(wèn)候語(yǔ) 建議問(wèn)題 模型選擇器與活躍態(tài)消息列表 輸入框ChatMessage渲染用戶氣泡或助手消息工具塊 MarkdownChatMarkdown客戶端 Markdown 渲染react-markdownremark-gfm使用設(shè)計(jì) token 樣式ToolCallBlock/ToolCallGroup內(nèi)聯(lián)工具調(diào)用可視化——運(yùn)行中spinner、已完成折疊勾選 摘要、已完成展開(kāi)輸入/輸出 JSONArtifactPanel右側(cè)滑入面板多 Artifact 分 Tab按類型渲染Markdown、Mermaid 圖、搜索結(jié)果、原始 JSONModelSelector緊湊 popover切換 Provider/模型并內(nèi)聯(lián)添加 API KeyConversationHistory下拉列出歷史會(huì)話支持刪除、新建、恢復(fù)、fork、固定等操作頁(yè)面結(jié)構(gòu)倉(cāng)庫(kù)落地頁(yè)/repos/[id]就是聊天界面緊湊頭部倉(cāng)庫(kù)名 commit 徽標(biāo) 分支徽標(biāo)、ChatInterface占滿剩余視口高度、側(cè)邊欄導(dǎo)航項(xiàng)由 Overview 改為 Chat。倉(cāng)庫(kù)的其他子頁(yè)graph、wiki、coverage 等保持不變。10. Provider 專屬說(shuō)明Anthropic使用client.messages.stream()原生 Anthropic 消息格式。OpenAI 格式消息需轉(zhuǎn)換工具結(jié)果轉(zhuǎn)為user角色的tool_resultcontent block工具調(diào)用轉(zhuǎn)為tool_usecontent block。Agentic Loop 跑在 Chat Router。OpenAI使用client.chat.completions.create(streamTrue)。原生 OpenAI 格式幾乎無(wú)需轉(zhuǎn)換。工具調(diào)用片段在流 chunk 中累積完整后一次性以tool_start事件發(fā)出。Agentic Loop 跑在 Chat Router。Gemini使用client.models.generate_content()非流式在線程池中執(zhí)行見(jiàn) packages/core/src/repowise/core/providers/llm/gemini.py。Agentic Loop 在stream_chat()內(nèi)部運(yùn)行Gemini 的 API 在回放對(duì)話歷史中的 function call 時(shí)必須攜帶thought_signature若經(jīng) Router 做 OpenAI 格式往返會(huì)丟失該簽名因此內(nèi)部循環(huán)全程使用原生Content對(duì)象通過(guò)tool_executor回調(diào)執(zhí)行工具并產(chǎn)出tool_start/tool_result事件。tool_executor參數(shù)對(duì) Gemini 是必需的缺失時(shí)它會(huì)yield一個(gè)stop讓調(diào)用方接管循環(huán)但注釋明確這會(huì)在下一次往返時(shí)因thought_signature缺失而失敗。Ollama使用 OpenAI 兼容端點(diǎn)localhost:11434/v1經(jīng)AsyncOpenAI調(diào)用流式模式與 OpenAI 一致無(wú)需 API Key。Agentic Loop 跑在 Chat Router。LiteLLM使用litellm.acompletion(streamTrue)OpenAI 兼容流式輸出。Agentic Loop 跑在 Chat Router。附注推理類模型的溫度參數(shù)兼容值得補(bǔ)充的是流式聊天與生成共用 Provider 層的溫度兼容策略見(jiàn) base.py推理時(shí)代的部分模型如gpt-5、o1、o3、o4系列Anthropic Opus/Sonnet 5 系列等會(huì)拒絕顯式temperature并返回 400。temperature_kwargs()對(duì)已知前綴直接跳過(guò)該參數(shù)is_temperature_rejection()/remember_temperature_rejection()則在運(yùn)行時(shí)從第一次拒絕中「學(xué)習(xí)」新模型并加入進(jìn)程內(nèi)緩存避免每次多付一次失敗的調(diào)用。這是跨生成與聊天兩條路徑的共享底層邏輯。結(jié)語(yǔ)與進(jìn)一步閱讀Repowise Codebase Chat 的核心價(jià)值在于「把 MCP 工具面安全地投影給一個(gè)帶流式的 Agent 循環(huán)」倉(cāng)庫(kù)級(jí)工具配置決定能力邊界ChatProvider協(xié)議讓不同廠商的流式/工具語(yǔ)義歸一化SSE 協(xié)議與前端useChat狀態(tài)機(jī)保證「生成過(guò)程可見(jiàn)、結(jié)果可回放」。若想深入源碼建議按以下順序閱讀聊天路由與 Agentic Looppackages/server/src/repowise/server/routers/chat.py工具注冊(cè)表與執(zhí)行合約packages/server/src/repowise/server/chat_tools.pyProvider 協(xié)議與事件類型packages/core/src/repowise/core/providers/llm/base.pyProvider 配置解析鏈packages/server/src/repowise/server/provider_config.py數(shù)據(jù)庫(kù)遷移packages/core/alembic/versions/0005_chat_conversations.py前端 API 層packages/api-client/src/chat.ts、packages/web/src/lib/hooks/use-chat.ts架構(gòu)級(jí)說(shuō)明docs/architecture/chat.md、docs/architecture/ARCHITECTURE.md贊分享【免費(fèi)下載鏈接】repowiseCodebase intelligence for AI and humans: code health scores, auto-generated docs, git analytics, dead code detection, and architectural decisions via MCP.項(xiàng)目地址https://gitcode.com/gh_mirrors/re/repowise點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Hoppscotch 快速上手三步部署自托管 API 調(diào)試平臺(tái)的實(shí)操指南Hoppscotch 快速上手三步部署自托管 API 調(diào)試平臺(tái)的實(shí)操指南 Hoppscotch 是一個(gè)開(kāi)源 API 開(kāi)發(fā)工具支持 REST、GraphQL、開(kāi)發(fā)工具接口測(cè)試前端后端CLI基于 n8n 的 Tech Stack Expert 對(duì)話式技術(shù)選型 Agent工作流架構(gòu)、系統(tǒng)提示詞與實(shí)戰(zhàn)接入解析基于 n8n 的 Tech Stack Expert 對(duì)話式技術(shù)選型 Agent工作流架構(gòu)、系統(tǒng)提示詞與實(shí)戰(zhàn)接入解析 本文以 oTTomator Live A示例工程ruflo 性能優(yōu)化 Agent 實(shí)戰(zhàn)指南基于 sublinear 算法的 Performance Optimizer 架構(gòu)、MCP 工具與集成模式ruflo 性能優(yōu)化 Agent 實(shí)戰(zhàn)指南基于 sublinear 算法的 Performance Optimizer 架構(gòu)、MCP 工具與集成模式 本指南以人工智能AI Agent多智能體Agent 編排Agent 記憶工具調(diào)用代碼智能體MCP 服務(wù)AI 評(píng)測(cè)上一篇【免費(fèi)下載】 探索Windows驅(qū)動(dòng)存儲(chǔ)庫(kù)的利器Driver Store ExplorerRAPR下一篇終極指南如何使用Go-libp2p構(gòu)建去中心化網(wǎng)絡(luò)應(yīng)用創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考