Hermes Agent接入DeepSeek V4的完整指南
一、背景:為什么要在 Hermes Agent 中用 DeepSeek V4
1.1 Hermes Agent 是模型無關(guān)的
Hermes Agent 設(shè)計(jì)了一個(gè)很重要的特性——模型無關(guān)(Model-Agnostic)。它內(nèi)部有一套 Transport 適配器層,把不同廠商的 API 差異封裝在內(nèi)部,對(duì)上層暴露統(tǒng)一接口。
這意味著切換模型不需要改代碼,只需要改配置。
目前 Hermes Agent 支持的 API 模式:
| API 模式 | 適用模型 |
|---|---|
chat_completions | OpenAI、DeepSeek、OpenRouter、小米、智譜…… |
anthropic_messages | Anthropic Claude、MiniMax 的 Anthropic 兼容接口 |
codex_responses | OpenAI Codex、xAI |
bedrock_converse | AWS Bedrock |
DeepSeek V4 提供的是標(biāo)準(zhǔn)的 OpenAI 兼容 API,所以走 chat_completions 模式,這是最簡(jiǎn)單的接入路徑。
1.2 我們要做什么
說白了就三步:
1. 配置中指定 provider 為 deepseek
2. 配置中指定 model 為 deepseek-v4-flash(或 deepseek-v4-pro)
3. 設(shè)置 DEEPSEEK_API_KEY 環(huán)境變量
就這么多。不需要改一行 Python 代碼。
二、準(zhǔn)備工作
開始之前,確認(rèn)以下條件:
| 項(xiàng)目 | 要求 |
|---|---|
| Hermes Agent | 已克隆到本地(二開倉(cāng)庫(kù) main 分支) |
| Python 環(huán)境 | venv 可用(./venv/Scripts/python.exe) |
| DeepSeek 賬號(hào) | 已注冊(cè)并創(chuàng)建 API Key |
| 網(wǎng)絡(luò) | 能訪問 https://api.deepseek.com |
如果你用的我們的二開倉(cāng)庫(kù),前兩個(gè)條件已經(jīng)滿足。
三、具體配置步驟
步驟 1:注冊(cè) DeepSeek 賬號(hào),獲取 API Key
打開 https://platform.deepseek.com/api_keys,注冊(cè)賬號(hào),創(chuàng)建一個(gè) API Key。
創(chuàng)建成功后你會(huì)看到一串以 sk- 開頭的密鑰,復(fù)制它。
步驟 2:設(shè)置環(huán)境變量
找到項(xiàng)目根目錄的 .env 文件,添加一行:
DEEPSEEK_API_KEY=sk-你的密鑰 # 可選:自定義 API 地址(默認(rèn) https://api.deepseek.com/v1,通常不需要改) # DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
注意:.env 文件默認(rèn)被 .gitignore 忽略,不會(huì)提交到倉(cāng)庫(kù),密鑰是安全的。
步驟 3:修改 config.yaml
編輯 hermes_workspace/config.yaml,找到 model: 配置段,修改為:
model: default: deepseek-v4-flash # 使用 V4 Flash 版本 provider: deepseek # 提供商設(shè)為 deepseek base_url: https://api.deepseek.com/v1
三個(gè)字段的含義:
| 字段 | 值 | 作用 |
|---|---|---|
default | deepseek-v4-flash | 告訴 Hermes 用哪個(gè)模型 |
provider | deepseek | 告訴 Hermes 走哪個(gè)提供商的認(rèn)證和路由 |
base_url | https://api.deepseek.com/v1 | 告訴 Hermes API 地址在哪 |
三個(gè)字段缺一不可,少一個(gè) Hermes 就無法確定怎么連。
步驟 4:驗(yàn)證 API 連通性
在終端運(yùn)行以下命令,確認(rèn) DeepSeek API 能正常響應(yīng):
curl -s https://api.deepseek.com/v1/models \ -H "Authorization: Bearer $DEEPSEEK_API_KEY" \ -H "Content-Type: application/json"
正常返回:
{
"object": "list",
"data": [
{"id": "deepseek-v4-flash", "object": "model", "owned_by": "deepseek"},
{"id": "deepseek-v4-pro", "object": "model", "owned_by": "deepseek"}
]
}
能看到兩個(gè)模型 ID,說明 API Key 有效,網(wǎng)絡(luò)連通。
再測(cè)試一下對(duì)話:
curl -s https://api.deepseek.com/v1/chat/completions \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [{"role": "user", "content": "你好,請(qǐng)用一句話介紹自己"}],
"max_tokens": 100
}'
如果返回包含 choices[0].message.content,說明模型正常響應(yīng)。
步驟 5:?jiǎn)?dòng) Hermes Agent 測(cè)試
激活虛擬環(huán)境,啟動(dòng)交互式會(huì)話:
# Windows .\venv\Scripts\activate # Linux/Mac source venv/bin/activate # 啟動(dòng) Hermes python hermes
輸入任意問題測(cè)試。如果你看到了正?;貜?fù),說明配置成功!
預(yù)期結(jié)果:
Provider: deepseek API mode: chat_completions Model: deepseek-v4-flash 你: 你好 Hermes: 你好!有什么我可以幫你的嗎?
四、進(jìn)階配置
4.1 切換到 Pro 版本
如果任務(wù)需要更強(qiáng)的推理能力(復(fù)雜數(shù)學(xué)、長(zhǎng)文檔分析),改一行即可:
model: default: deepseek-v4-pro # 從 flash 改為 pro provider: deepseek base_url: https://api.deepseek.com/v1
Pro 的激活參數(shù)是 Flash 的 3.8 倍(49B vs 13B),推理深度更強(qiáng),但價(jià)格也貴 12 倍。
4.2 通過 OpenRouter 中轉(zhuǎn)
如果你已經(jīng)在用 OpenRouter,可以不切換 provider,直接改模型名:
model: default: deepseek/deepseek-v4-flash # 注意 OpenRouter 要用 vendor/model 格式 provider: openrouter # 保持 openrouter 不變 base_url: https://openrouter.ai/api/v1
OpenRouter 上的路由會(huì)自動(dòng)把請(qǐng)求轉(zhuǎn)發(fā)到 DeepSeek。
4.3 使用 Anthropic 兼容接口
DeepSeek 也提供了 Anthropic 兼容的 API 端點(diǎn),如果你習(xí)慣了 Anthropic 的接口格式,可以用這個(gè):
model: default: deepseek-v4-flash provider: deepseek base_url: https://api.deepseek.com/anthropic # 注意這個(gè) URL
當(dāng) base_url 以 /anthropic 結(jié)尾時(shí),Hermes Agent 會(huì)自動(dòng)檢測(cè)并切換到 anthropic_messages 模式。
4.4 雙模型策略:默認(rèn) Flash,復(fù)雜任務(wù)升 Pro
這是最經(jīng)濟(jì)的用法——日常對(duì)話用 Flash(極低成本),遇到復(fù)雜推理時(shí)手動(dòng)切換到 Pro。
在 Hermes 會(huì)話中通過 /model 命令切換:
你: /model deepseek-v4-pro Hermes: 模型已切換為 deepseek-v4-pro 你: 幫我分析這篇論文的數(shù)學(xué)推導(dǎo)... Hermes: [使用 Pro 進(jìn)行深度推理]
用完后切回 Flash:
你: /model deepseek-v4-flash
這樣可以大幅降低成本——Flash 的價(jià)格只有 Pro 的 1/12。
接下來的內(nèi)容,我們深入 Hermes Agent 的源碼,看一條消息從"用戶輸入"到"DeepSeek 響應(yīng)"的完整旅程。
涉及的源碼文件和關(guān)鍵行號(hào):
| 環(huán)節(jié) | 文件 | 關(guān)鍵行 |
|---|---|---|
| 配置加載 | run_agent.py AIAgent.init | L833-L1059 |
| Provider 識(shí)別 | run_agent.py api_mode 判斷 | L977-L1008 |
| 模型名歸一化 | hermes_cli/model_normalize.py | L147-L179 |
| 憑證加載 | agent/credential_pool.py | L1262-L1338 |
| Transport 選擇 | agent/transports/__init__.py | L14-L57 |
| API 調(diào)用構(gòu)建 | agent/transports/chat_completions.py | L75-L162 |
| Reasoning 處理 | run_agent.py | L7826-L7885 |
五、配置加載流程:從 config.yaml 到 AIAgent
5.1 CLI 啟動(dòng)時(shí)發(fā)生了什么
當(dāng)你運(yùn)行 python hermes 時(shí):
1. CLI 入口(cli.py)讀取 hermes_workspace/config.yaml
2. 從 config 中提取 model.default → "deepseek-v4-flash"
3. 從 config 中提取 model.provider → "deepseek"
4. 從 config 中提取 model.base_url → "https://api.deepseek.com/v1"
5. 將這些參數(shù)傳給 AIAgent.__init__()
簡(jiǎn)化后的偽代碼:
# cli.py(簡(jiǎn)化)
config = load_config("hermes_workspace/config.yaml")
model_cfg = config.get("model", {})
agent = AIAgent(
model=model_cfg.get("default", "deepseek-v4-flash"),
provider=model_cfg.get("provider", "deepseek"),
base_url=model_cfg.get("base_url", "https://api.deepseek.com/v1"),
)5.2 AIAgent 初始化
AIAgent.__init__() 收到這三個(gè)參數(shù)后,會(huì)做一系列關(guān)鍵判斷。我們重點(diǎn)關(guān)注幾個(gè)核心屬性的賦值:
# run_agent.py 第 941-1008 行(簡(jiǎn)化) self.model = model # "deepseek-v4-flash" self.base_url = base_url or "" # "https://api.deepseek.com/v1" self.provider = provider.strip().lower() # "deepseek"
六、Provider 識(shí)別:如何確定走哪個(gè) API
這是最關(guān)鍵的一步。Hermes Agent 根據(jù) provider 和 base_url 來決定使用哪種 API 模式。
6.1 api_mode 判斷鏈
api_mode 決定了使用哪個(gè) Transport 適配器。判斷邏輯在 run_agent.py 第 977-1008 行:
# run_agent.py 第 977 行
if api_mode in {"chat_completions", "codex_responses", "anthropic_messages", "bedrock_converse"}:
# 如果調(diào)用者明確指定了 api_mode,直接用
self.api_mode = api_mode
elif self.provider == "openai-codex":
self.api_mode = "codex_responses"
elif self.provider == "xai":
self.api_mode = "codex_responses"
elif self.provider == "anthropic":
self.api_mode = "anthropic_messages"
elif self._base_url_lower.rstrip("/").endswith("/anthropic"):
# URL 以 /anthropic 結(jié)尾 → Anthropic 兼容模式
self.api_mode = "anthropic_messages"
elif self.provider == "bedrock":
self.api_mode = "bedrock_converse"
else:
# 以上都不匹配 → 默認(rèn)走 chat_completions
self.api_mode = "chat_completions"DeepSeek 走的是哪條分支?
我們的配置是:
provider = "deepseek"base_url = "https://api.deepseek.com/v1"
對(duì)照判斷鏈:
- ? api_mode 未明確指定
- ? provider != “openai-codex”
- ? provider != “xai”
- ? provider != “anthropic”
- ? base_url 不以
/anthropic結(jié)尾 - ? provider != “bedrock”
- ? 所有條件都不滿足 → 走 else →
chat_completions
6.2 為什么這很重要?
chat_completions 模式使用的是 OpenAI SDK,而 DeepSeek 的 API 是 OpenAI 兼容的,所以天然適配。
如果錯(cuò)誤地走了 anthropic_messages 模式,Hermes 會(huì)用 Anthropic SDK 去發(fā)請(qǐng)求,但 DeepSeek 的 OpenAI 端點(diǎn)不認(rèn)識(shí) Anthropic 的請(qǐng)求格式,會(huì)返回 400 錯(cuò)誤。
小結(jié):判斷鏈的本質(zhì)是一個(gè)路由表。每個(gè) provider 按其特征(名稱、URL)被路由到正確的 API 模式。DeepSeek 的特征是"OpenAI 兼容但沒有特殊標(biāo)識(shí)",所以走了默認(rèn)的 chat_completions。
七、模型名歸一化:為什么 deepseek-v4-flash 能直接用
你可能注意到,我們的配置寫的是 deepseek-v4-flash,但早期 Hermes Agent 版本只認(rèn)識(shí) deepseek-chat。為什么現(xiàn)在可以直接用 V4 模型名?
7.1 歷史包袱
早期的 Hermes Agent 把所有非推理的 DeepSeek 輸入都折疊為 deepseek-chat,這個(gè)模型在 DeepSeek 自己的 API 上對(duì)應(yīng) V3。也就是說:
用戶寫 deepseek-v4-flash → 被折疊為 deepseek-chat → 實(shí)際調(diào)用的是 V3
這對(duì)用戶來說是個(gè)隱蔽的坑——配置了 V4,結(jié)果用的還是 V3。
7.2 歸一化規(guī)則
這個(gè)問題在最近的版本中已經(jīng)修復(fù)?,F(xiàn)在的歸一化邏輯在 hermes_cli/model_normalize.py 第 147-179 行:
_DEEPSEEK_CANONICAL_MODELS = frozenset({
"deepseek-chat", # V3
"deepseek-reasoner", # R1
"deepseek-v4-pro", # V4 Pro
"deepseek-v4-flash", # V4 Flash
})
_DEEPSEEK_V_SERIES_RE = re.compile(r"^deepseek-v\d+([-.].+)?$")
def _normalize_for_deepseek(model_name: str) -> str:
bare = _strip_vendor_prefix(model_name).lower()
# 規(guī)則 1:已經(jīng)是規(guī)范的模型名 → 原樣返回
if bare in _DEEPSEEK_CANONICAL_MODELS:
return bare
# 規(guī)則 2:匹配 V 系列模式(deepseek-v<數(shù)字>...)→ 原樣返回
if _DEEPSEEK_V_SERIES_RE.match(bare):
return bare
# 規(guī)則 3:包含推理關(guān)鍵詞(r1, think, reasoning...)→ deepseek-reasoner
for keyword in _DEEPSEEK_REASONER_KEYWORDS:
if keyword in bare:
return "deepseek-reasoner"
# 規(guī)則 4:其他所有 → deepseek-chat(V3)
return "deepseek-chat"為什么我們的配置能正確傳遞?來看匹配過程:
bare = "deepseek-v4-flash"(去掉可能的前綴)- 檢查是否在
_DEEPSEEK_CANONICAL_MODELS→ 在!因?yàn)?deepseek-v4-flash是規(guī)范名之一 - 匹配 V 系列正則 → 也匹配,但規(guī)則 1 先命中
- 返回
"deepseek-v4-flash"原樣
同樣,deepseek-v4-pro 也是規(guī)范名,也會(huì)原樣傳遞。
7.3 調(diào)用鏈
# run_agent.py 第 1017-1024 行
from hermes_cli.model_normalize import normalize_model_for_provider
# 如果 provider 不是聚合器(OpenRouter 那種),就走歸一化
if self.provider not in _AGGREGATOR_PROVIDERS:
self.model = normalize_model_for_provider(self.model, self.provider)
# → normalize_model_for_provider("deepseek-v4-flash", "deepseek")
# → _normalize_for_deepseek("deepseek-v4-flash")
# → "deepseek-v4-flash"(原樣返回)小結(jié):模型名歸一化確保用戶輸入被映射為 API 能識(shí)別的模型 ID。V 系列 ID(v4-pro、v4-flash 和未來的 v5-*)會(huì)原樣傳遞,只有模糊輸入(如 deepseek-r1)才會(huì)被映射到規(guī)范名。
八、憑證加載:DEEPSEEK_API_KEY 是如何被找到的
改了配置,加了環(huán)境變量,但 Hermes Agent 是怎么知道要用 DEEPSEEK_API_KEY 的?
8.1 提供商注冊(cè)表
在 hermes_cli/auth.py 中,有一個(gè)提供商注冊(cè)表 PROVIDER_REGISTRY,記錄了每個(gè)提供商的信息:
# hermes_cli/auth.py 第 272 行(簡(jiǎn)化)
ProviderConfig(
name="deepseek",
api_key_env_vars=("DEEPSEEK_API_KEY",), # 從哪個(gè)環(huán)境變量讀 key
base_url_env_var="DEEPSEEK_BASE_URL", # 可選:自定義 base_url
inference_base_url="https://api.deepseek.com/v1", # 默認(rèn) API 地址
auth_type="api_key", # 認(rèn)證方式
)這里的關(guān)鍵信息是:DeepSeek 的 API Key 從 DEEPSEEK_API_KEY 環(huán)境變量讀取。
8.2 憑證池加載
當(dāng) Hermes Agent 需要調(diào)用 API 時(shí),會(huì)觸發(fā)憑證加載:
# agent/credential_pool.py 第 1262 行(簡(jiǎn)化)
def _seed_from_env(provider, entries):
# 查詢 PROVIDER_REGISTRY 獲取該提供商的配置
pconfig = PROVIDER_REGISTRY.get(provider) # provider = "deepseek"
# 遍歷所有可能的環(huán)境變量名
for env_var in pconfig.api_key_env_vars: # → ("DEEPSEEK_API_KEY",)
token = os.getenv(env_var, "").strip() # → 從環(huán)境變量讀取
if not token:
continue
# 將憑證寫入憑證池
entries.append({
"source": f"env:{env_var}",
"auth_type": "api_key",
"access_token": token, # 你的 sk-xxx
"base_url": pconfig.inference_base_url,
})8.3 讀取優(yōu)先級(jí)
Hermes Agent 讀取憑證的順序:
1. 環(huán)境變量(DEEPSEEK_API_KEY)
2. ~/.hermes/.env 文件
3. 項(xiàng)目根目錄 .env 文件
4. hermes auth 命令手動(dòng)添加的憑證
如果多個(gè)來源都有值,優(yōu)先級(jí)高的覆蓋優(yōu)先級(jí)低的。
8.4 驗(yàn)證憑證是否加載成功
運(yùn)行以下命令查看憑證池狀態(tài):
python -c "
from hermes_cli.env_loader import load_hermes_dotenv
from pathlib import Path
load_hermes_dotenv(hermes_home=Path.home()/'.hermes', project_env=Path.cwd()/'.env')
import os
print('DEEPSEEK_API_KEY loaded:', bool(os.getenv('DEEPSEEK_API_KEY')))
"
如果輸出 True,說明憑證加載成功。
小結(jié):憑證加載是自動(dòng)的。Hermes Agent 根據(jù) provider: deepseek 查找注冊(cè)表,找到對(duì)應(yīng)的環(huán)境變量名 DEEPSEEK_API_KEY,然后從環(huán)境中讀取。你只需要確保環(huán)境變量已設(shè)置即可。
九、Transport 選擇:chat_completions 模式詳解
確定了 api_mode = "chat_completions" 后,Hermes Agent 需要選擇一個(gè) Transport 來處理 API 請(qǐng)求。
9.1 Transport 注冊(cè)表
Transport 采用注冊(cè)表模式,每個(gè) api_mode 對(duì)應(yīng)一個(gè) Transport 類:
# agent/transports/__init__.py
_REGISTRY = {
"chat_completions": ChatCompletionsTransport,
"anthropic_messages": AnthropicTransport,
"codex_responses": CodexTransport,
"bedrock_converse": BedrockTransport,
}
def get_transport(api_mode):
cls = _REGISTRY.get(api_mode)
return cls() # 返回一個(gè) Transport 實(shí)例9.2 Transport 管道
每個(gè) Transport 遵循相同的四步管道:
convert_messages → convert_tools → build_kwargs → normalize_response
對(duì)于 ChatCompletionsTransport,消息和工具已經(jīng)是 OpenAI 格式,所以轉(zhuǎn)換步驟幾乎是恒等變換:
# agent/transports/chat_completions.py
class ChatCompletionsTransport(ProviderTransport):
def convert_messages(self, messages, **kwargs):
# 消息已經(jīng)是 OpenAI 格式,只需清理 Codex 殘留字段
return messages # 幾乎就是原樣返回
def convert_tools(self, tools):
# 工具定義已經(jīng)是 OpenAI 格式
return tools # 原樣返回
def build_kwargs(self, model, messages, tools, **params):
# 組裝 API 調(diào)用參數(shù)
kwargs = {
"model": model, # "deepseek-v4-flash"
"messages": messages, # OpenAI 格式消息
"tools": tools, # 工具定義
"max_tokens": ...,
"temperature": ...,
"extra_body": ..., # 提供商特定參數(shù)
}
return kwargs
def normalize_response(self, response):
# 將 DeepSeek 的響應(yīng)標(biāo)準(zhǔn)化為統(tǒng)一格式
return NormalizedResponse(
content=response.choices[0].message.content,
tool_calls=tool_calls,
finish_reason=response.choices[0].finish_reason,
reasoning=getattr(response.choices[0].message, "reasoning_content", None),
usage=Usage(
prompt_tokens=response.usage.prompt_tokens,
completion_tokens=response.usage.completion_tokens,
),
)9.3 build_kwargs 的 Provider 特定配置
build_kwargs 是 Transport 中最復(fù)雜的方法。對(duì)于 DeepSeek,它需要處理幾個(gè)特殊邏輯:
max_tokens 默認(rèn)值:DeepSeek 不強(qiáng)制要求 max_tokens,但 Hermes 會(huì)設(shè)置一個(gè)合理的默認(rèn)值。
temperature:DeepSeek 支持 temperature 參數(shù)。Hermes 會(huì)根據(jù)配置傳入。
extra_body:有些提供商需要在 extra_body 中傳遞額外參數(shù)。對(duì)于 DeepSeek,通常是空的。
小結(jié):Transport 層封裝了所有 API 差異。ChatCompletionsTransport 是最簡(jiǎn)單的 Transport,因?yàn)?DeepSeek 和 OpenAI 的接口幾乎一致。如果換成 Anthropic 的 Transport,消息格式轉(zhuǎn)換就復(fù)雜得多。
十、API 調(diào)用構(gòu)建:請(qǐng)求是怎么組裝并發(fā)出的
10.1 客戶端創(chuàng)建
實(shí)際發(fā)請(qǐng)求的是 OpenAI SDK:
# run_agent.py(簡(jiǎn)化)
from openai import OpenAI
client = OpenAI(
api_key=credential.access_token, # 你的 sk-xxx
base_url="https://api.deepseek.com/v1", # 從 config.yaml 讀的
)10.2 完整請(qǐng)求鏈
一條消息從用戶輸入到 DeepSeek API 的完整路徑:
用戶輸入 "你好"
→ CLI 讀取輸入
→ AIAgent.run_conversation("你好")
→ 構(gòu)建 messages 列表 [{"role": "user", "content": "你好"}]
→ 調(diào)用 self._call_llm()
→ 獲取 Transport: ChatCompletionsTransport
→ transport.build_kwargs(model, messages, tools)
→ 組裝 kwargs
→ client.chat.completions.create(**kwargs)
→ HTTP POST https://api.deepseek.com/v1/chat/completions
→ 請(qǐng)求體: {"model": "deepseek-v4-flash", "messages": [...], ...}
→ DeepSeek API 返回響應(yīng)
→ transport.normalize_response(response)
→ 提取 content, tool_calls, usage
→ AIAgent 處理返回結(jié)果
→ 輸出到終端
10.3 重試與錯(cuò)誤處理
Hermes Agent 有自動(dòng)重試機(jī)制。當(dāng) API 返回錯(cuò)誤時(shí):
# 重試策略(簡(jiǎn)化)
retry_on_status = {429, 502, 503, 529} # 限流、網(wǎng)關(guān)超時(shí)、服務(wù)不可用
for attempt in range(max_retries): # 默認(rèn)最多重試 3 次
try:
response = client.chat.completions.create(**kwargs)
return response
except APIError as e:
if e.status_code in retry_on_status:
wait = jittered_backoff(attempt) # 退避等待
time.sleep(wait)
else:
raise # 非重試錯(cuò)誤直接拋出十一、響應(yīng)處理:DeepSeek 的特殊處理
11.1 reasoning_content
DeepSeek V4 支持"思考模式"——在返回最終答案之前,模型會(huì)先輸出推理過程。這些推理內(nèi)容放在 reasoning_content 字段中。
{
"choices": [{
"message": {
"content": "OK",
"reasoning_content": "用戶要求只回復(fù) OK,所以直接回答 OK"
},
"finish_reason": "stop"
}]
}
11.2 Hermes 如何保留推理內(nèi)容
在 run_agent.py 第 7826 行,有一個(gè)專門的檢測(cè)方法:
def _needs_deepseek_tool_reasoning(self) -> bool:
"""檢測(cè)當(dāng)前是否使用 DeepSeek 的思考模式"""
provider = (self.provider or "").lower()
model = (self.model or "").lower()
return (
provider == "deepseek" # provider 是 deepseek
or "deepseek" in model # 模型名包含 deepseek
or base_url_host_matches(self._base_url_lower, "api.deepseek.com") # 域名匹配
)這個(gè)檢測(cè)在三個(gè)地方被使用:
- 響應(yīng)標(biāo)準(zhǔn)化時(shí):從
reasoning_content字段提取推理過程,存入消息的reasoning字段 - 工具調(diào)用消息回顯時(shí):DeepSeek 的 API 要求在工具調(diào)用消息中也要包含
reasoning_content字段,否則會(huì)報(bào) 400 錯(cuò)誤 - 持久化時(shí):推理內(nèi)容會(huì)被保存到對(duì)話歷史中,保證跨會(huì)話的連續(xù)性
# 在消息持久化前,補(bǔ)充 reasoning_content(簡(jiǎn)化)
if self._needs_deepseek_tool_reasoning():
if assistant_msg.get("tool_calls"):
# DeepSeek 要求在 tool_calls 消息中也有 reasoning_content
api_msg["reasoning_content"] = ""11.3 三條檢測(cè)路徑
| 檢測(cè)方式 | 示例 | 匹配 |
|---|---|---|
provider == "deepseek" | config 中 provider 設(shè)為 deepseek | ? |
"deepseek" in model | 模型名含 deepseek | ? |
api.deepseek.com 域名 | base_url 指向 deepseek 域名 | ? |
三條路徑只要有一條匹配,就會(huì)觸發(fā) reasoning_content 處理。這也是為什么我們配置 provider: deepseek 后,推理內(nèi)容能正常顯示。
小結(jié):DeepSeek 的 reasoning_content 不是標(biāo)準(zhǔn) OpenAI 格式的字段,但 Hermes Agent 通過專門的檢測(cè)邏輯,把它正確地保留下來了。這對(duì)于 Agent 場(chǎng)景很重要——推理軌跡在多輪工具調(diào)用中是關(guān)鍵上下文。
十二、圖解:一條消息的完整旅程
把前面的所有環(huán)節(jié)串起來,一條消息從"用戶輸入"到"DeepSeek 響應(yīng)"的完整鏈路:
┌─────────────────────────────────────────────────────────────────────┐
│ 用戶終端 (CLI) │
│ 輸入: "幫我查一下今天的天氣" │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CLI 入口 (cli.py) │
│ • 讀取 config.yaml → model: deepseek-v4-flash │
│ • 讀取 config.yaml → provider: deepseek │
│ • 讀取 config.yaml → base_url: https://api.deepseek.com/v1 │
│ • 讀取 .env → DEEPSEEK_API_KEY │
│ • 創(chuàng)建 AIAgent(model, provider, base_url) │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AIAgent.__init__() (run_agent.py) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ① Provider 識(shí)別 │ │
│ │ provider="deepseek" → 不匹配任何特殊條件 │ │
│ │ → api_mode = "chat_completions" │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ② 模型名歸一化 │ │
│ │ normalize_model_for_provider("deepseek-v4-flash", "deepseek")│ │
│ │ → _normalize_for_deepseek("deepseek-v4-flash") │ │
│ │ → "deepseek-v4-flash" (原樣返回) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ③ 憑證加載 │ │
│ │ PROVIDER_REGISTRY["deepseek"] → env_var: "DEEPSEEK_API_KEY" │ │
│ │ os.getenv("DEEPSEEK_API_KEY") → "sk-xxx" │ │
│ │ 寫入憑證池 → 后續(xù) API 調(diào)用使用 │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AIAgent.run_conversation() │
│ • 構(gòu)建 system prompt (Hermes 的默認(rèn)身份) │
│ • 構(gòu)建 messages: [{role: "user", content: "幫我查一下今天的天氣"}] │
│ • 調(diào)用 _call_llm() │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Transport 層 (chat_completions) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ChatCompletionsTransport.build_kwargs() │ │
│ │ → convert_messages(): 已經(jīng)是 OpenAI 格式,幾乎不變 │ │
│ │ → convert_tools(): 已經(jīng)是 OpenAI 格式,幾乎不變 │ │
│ │ → 組裝 kwargs: model, messages, tools, max_tokens, ... │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ OpenAI SDK client.chat.completions.create(**kwargs) │ │
│ │ → HTTP POST https://api.deepseek.com/v1/chat/completions │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ DeepSeek API Server │
│ • 接收請(qǐng)求 → 模型推理 → 生成響應(yīng) │
│ • 返回: {"choices": [{"message": {"content": "...", │
│ "reasoning_content": "..."}}], "usage": {...}} │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AIAgent 處理響應(yīng) │
│ • ChatCompletionsTransport.normalize_response() │
│ → 提取 content, tool_calls, reasoning_content │
│ → 標(biāo)準(zhǔn)化為 NormalizedResponse │
│ • 如果有 tool_calls → 執(zhí)行工具 → 繼續(xù)循環(huán) │
│ • 如果只有文本 → 返回給用戶 │
│ • DeepSeek 特殊處理: │
│ → _needs_deepseek_tool_reasoning() → True │
│ → 保留 reasoning_content 到消息歷史 │
│ → 工具調(diào)用消息補(bǔ)充 reasoning_content │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 用戶終端 (CLI) │
│ 輸出: "今天天氣晴朗,氣溫 22-28°C,適合戶外活動(dòng)。" │
└─────────────────────────────────────────────────────────────────────┘
這個(gè)流程中的關(guān)鍵檢查點(diǎn):
| 檢查點(diǎn) | 做什么 | 如果錯(cuò)了 |
|---|---|---|
| Provider 識(shí)別 | 確定 api_mode | API 格式不匹配,返回 400 |
| 模型名歸一化 | 確保模型名 API 能識(shí)別 | 路由到錯(cuò)誤的模型版本 |
| 憑證加載 | 獲取 API Key | 401 Unauthorized |
| Transport 構(gòu)建 | 組裝請(qǐng)求參數(shù) | 請(qǐng)求格式錯(cuò)誤 |
十三、常見問題排查
Q1:?jiǎn)?dòng)時(shí)提示 “Provider ‘deepseek’ not found”
原因:config.yaml 中 provider 拼寫錯(cuò)誤。
解決:檢查 provider 是否為 deepseek(全小寫)。
Q2:API 返回 401 Unauthorized
原因:DEEPSEEK_API_KEY 未設(shè)置或設(shè)置錯(cuò)誤。
排查步驟:
# 1. 檢查環(huán)境變量是否已加載 echo $DEEPSEEK_API_KEY # 2. 如果為空,檢查 .env 文件 grep DEEPSEEK_API_KEY .env # 3. 確保 .env 文件格式正確(不要有多余空格或引號(hào)) # 正確: DEEPSEEK_API_KEY=sk-xxx # 錯(cuò)誤: DEEPSEEK_API_KEY = "sk-xxx"
Q3:API 返回 400 Bad Request
原因:請(qǐng)求格式錯(cuò)誤。可能是 api_mode 選錯(cuò)了。
排查:檢查運(yùn)行日志中的 api_mode 是否為 chat_completions。如果顯示 anthropic_messages,說明 base_url 可能以 /anthropic 結(jié)尾,導(dǎo)致模式誤判。
Q4:響應(yīng)很慢或超時(shí)
原因:可能是網(wǎng)絡(luò)問題,或者模型在處理復(fù)雜推理。
解決:
- 檢查網(wǎng)絡(luò)連通性:
curl -I https://api.deepseek.com - 如果不需要推理,可以在請(qǐng)求中關(guān)閉思維鏈
- 切換到 Flash 版本,響應(yīng)速度更快
Q5:模型明明配置了 V4,但感覺能力像 V3
原因:如果通過 OpenRouter 路由,deepseek-chat 會(huì)映射到 V3。如果直接調(diào)用 DeepSeek API,deepseek-chat 也可能指向舊版本。
解決:始終使用 V 系列 ID:deepseek-v4-flash 或 deepseek-v4-pro,不要用 deepseek-chat。
Q6:工具調(diào)用(Tool Calls)失敗
原因:DeepSeek 的工具調(diào)用格式可能與標(biāo)準(zhǔn) OpenAI 有細(xì)微差異。
解決:檢查是否啟用了 Hermes 的 DeepSeek 特殊處理(_needs_deepseek_tool_reasoning)。如果沒有,可能需要確保 provider 正確設(shè)置為 deepseek。
十四、總結(jié)
操作回顧
接入 DeepSeek V4 只需要兩步配置 + 一個(gè)環(huán)境變量:
| 改動(dòng)項(xiàng) | 位置 | 內(nèi)容 |
|---|---|---|
| 添加 API Key | .env | DEEPSEEK_API_KEY=sk-xxx |
| 修改模型配置 | hermes_workspace/config.yaml | provider: deepseek |
default: deepseek-v4-flash | ||
base_url: https://api.deepseek.com/v1 |
源碼層面的三個(gè)核心檢測(cè)點(diǎn)
| 檢測(cè)點(diǎn) | 位置 | 作用 |
|---|---|---|
| Provider 識(shí)別 | run_agent.py:977-1008 | 確定 api_mode → 決定 Transport |
| 模型名歸一化 | model_normalize.py:147-179 | 確保模型名被 API 識(shí)別 |
| 憑證加載 | credential_pool.py:1262-1338 | 從環(huán)境變量讀取 API Key |
一句話總結(jié)
Hermes Agent 接入 DeepSeek V4,本質(zhì)就是在三個(gè)核心檢測(cè)點(diǎn)(Provider → Model → Credential)上提供了正確的信息,讓框架的自動(dòng)路由機(jī)制找到正確的 API 路徑。
這不僅是 DeepSeek 的接入方式,也是 Hermes Agent 接入任何新模型的標(biāo)準(zhǔn)模式——理解了這個(gè)流程,你就能輕松接入任何 OpenAI 兼容的模型。
以上就是Hermes Agent接入DeepSeek V4的完整指南的詳細(xì)內(nèi)容,更多關(guān)于Hermes Agent接入DeepSeek V4的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章

Hermes Agent接入DeepSeekV4的保姆級(jí)教程
本文介紹了Hermes接入DeepSeek-V4的教程,通過博查萬象ModelAPI配置,升級(jí)為更強(qiáng)的Agent,本文內(nèi)容包含了DeepSeekV4的頂配配置、DSA稀疏注意力機(jī)制等優(yōu)勢(shì)以及如何在Hermes中快2026-04-27
Mac從零部署Hermes Agent并接入飛書的保姆級(jí)教程
Hermes Agent 是 Nous Research 開源的 AI Agent 框架,和 OpenClaw 同類,最大特點(diǎn)是會(huì)自我成長(zhǎng),本文基于實(shí)際踩坑過程整理,從 Hermes 安裝到飛書 Bot + 飛書 CLI 完整打通,2026-04-22
基于Docker部署Hermes Agent并接入飛書機(jī)器人的完整指南
本文將圍繞開源項(xiàng)目 Hermes Agent,手把手帶你完成從部署到接入飛書機(jī)器人的完整流程,相比零散教程,本文不僅提供詳細(xì)步驟,還會(huì)補(bǔ)充關(guān)鍵原理說明與實(shí)踐建議,幫助你真正掌2026-04-17
Hermes Agent對(duì)接本地Ollama大模型的實(shí)現(xiàn)步驟(完全離線運(yùn)行)
本文詳細(xì)介紹了如何將Hermes-Agent與本地Ollama大模型對(duì)接,實(shí)現(xiàn)完全離線運(yùn)行,該方案解決了云端模型依賴API Key、隱私泄露等問題,適合企業(yè)內(nèi)部等敏感場(chǎng)景使用,具有一定的2026-04-17
Hermes Agent保姆級(jí)教程:安裝、遷移OpenClaw、接入飛書全流程
本文介紹了使用hermes-agent在云服務(wù)器上安裝并接入飛書的過程,首先,通過命令安裝hermos-agent,并選擇MiniMax模型服務(wù),然后,綁定飛書消息平臺(tái),并創(chuàng)建飛書機(jī)器人,最后,安裝2026-04-16
Hermes Agent 安裝教程(Mac+windows):看完就能去閑魚接單
Hermes Agent 必定是新一代的 OpenClaw,想想前一段時(shí)間多少人在閑魚吃到 OpenClaw 的紅利,接下來你也可以吃到 Hermes 的紅利2026-04-14
Hermes Agent接入飛書和企業(yè)微信的全流程指南
文章介紹了如何在Feishu和企業(yè)微信上創(chuàng)建自建應(yīng)用,配置應(yīng)用權(quán)限,使用HermesGateway設(shè)置聊天平臺(tái),并通過命令行進(jìn)行配對(duì)和測(cè)試,最后在企業(yè)微信中配置機(jī)器人并進(jìn)行對(duì)話測(cè)試,需2026-04-12








