1、api_key可以为空
2、环境命令补充
This commit is contained in:
parent
05ece1bffc
commit
0cd43c37a7
32
README.md
32
README.md
@ -68,7 +68,7 @@ packaging/
|
||||
- 实现人工确认入口:`confirm --decision approve|reject` 只处理待确认回滚。
|
||||
- 实现 checkpoint 自动保存和 `resume` 续跑:全局步骤、成功 IP、单 IP 已完成 action 会跳过。
|
||||
- 实现 LLM structured output 骨架:意图识别、参数抽取、部署计划生成。
|
||||
- 实现 OpenAI-compatible 真实 LLM client,支持 `base_url` / `api_key` / `model` 配置。
|
||||
- 实现 OpenAI-compatible 真实 LLM client,支持 `base_url` / `model` 配置,`api_key` 可为空。
|
||||
- 固化真实 LLM 提示词:意图识别、参数抽取、部署计划生成均要求 JSON structured output。
|
||||
- 增加规则 fallback `RuleBasedLlmClient`,用于本地开发和测试。
|
||||
- 增加 LLM 输出 guardrails,禁止计划中出现可执行脚本命令和非法 action。
|
||||
@ -90,11 +90,12 @@ packaging/
|
||||
|
||||
## LLM 配置
|
||||
|
||||
默认不配置 LLM 时,`analyze` 使用本地规则 fallback。配置真实 LLM 后,会走 OpenAI-compatible `/chat/completions`:
|
||||
默认不配置 LLM 时,`analyze` 使用本地规则 fallback。配置真实 LLM 后,会走 OpenAI-compatible `/chat/completions`。
|
||||
|
||||
`base_url` 和 `model` 必填;`api_key` 可为空。如果模型服务不需要鉴权,不配置 `PAM_LLM_API_KEY` 或不传 `--llm-api-key` 即可,Agent 不会发送 `Authorization` 请求头。
|
||||
|
||||
```powershell
|
||||
$env:PAM_LLM_BASE_URL="https://your-llm.example.com/v1"
|
||||
$env:PAM_LLM_API_KEY="your-api-key"
|
||||
$env:PAM_LLM_MODEL="your-model-name"
|
||||
|
||||
python -m pam_deploy_graph.cli analyze --config doc_scripts/config.txt.example --text "请用 MCP 预演部署 HET PAM Node 版本 2.0.5,不要动环境"
|
||||
@ -107,12 +108,17 @@ python -m pam_deploy_graph.cli analyze \
|
||||
--config doc_scripts/config.txt.example \
|
||||
--text "请用 MCP 预演部署 HET PAM Node 版本 2.0.5,不要动环境" \
|
||||
--llm-base-url https://your-llm.example.com/v1 \
|
||||
--llm-api-key your-api-key \
|
||||
--llm-model your-model-name
|
||||
```
|
||||
|
||||
真实 LLM 调用位置在 `pam_deploy_graph/llm/openai_compatible.py`,提示词在 `pam_deploy_graph/llm/prompts.py`。发送给 LLM 的 `base_params` 会脱敏,`CLIENT_SECRET` 不会进入 prompt;本地生成计划后仍会执行 guardrails 校验。
|
||||
|
||||
如果服务需要鉴权,再补充:
|
||||
|
||||
```bash
|
||||
export PAM_LLM_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
## MCP Client 配置
|
||||
|
||||
CLI/chat 已支持通过 `--mcp-config` 直接加载 MCP 配置。常用场景只需要配置 MCP `server_url` 和独立鉴权信息;Agent 会连接 MCP server,调用 `list_tools` 自动发现 server 暴露的 tools,再按 action 名自动匹配。
|
||||
@ -183,6 +189,24 @@ agent = PamDeployAgent(mcp_runner=runner)
|
||||
|
||||
## 使用方式
|
||||
|
||||
开发项目迁移到新环境后,推荐先安装完整开发依赖:
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
python -m pip install -e ".[mcp,chat,test]"
|
||||
pytest -q
|
||||
```
|
||||
|
||||
Windows PowerShell 激活虚拟环境使用:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
```
|
||||
|
||||
基础要求:Python 3.11+。如果要执行 Linux 脚本 action,运行环境还需要 `bash` 和 `curl`;如果要构建 Linux 解压即用包,请在 Linux x86_64 构建机上执行打包脚本。
|
||||
|
||||
整体逻辑结构流程图:
|
||||
|
||||
```text
|
||||
|
||||
@ -26,8 +26,6 @@ def build_llm_client(
|
||||
missing = []
|
||||
if not actual_base_url:
|
||||
missing.append("base_url")
|
||||
if not actual_api_key:
|
||||
missing.append("api_key")
|
||||
if not actual_model:
|
||||
missing.append("model")
|
||||
if missing:
|
||||
|
||||
@ -43,8 +43,6 @@ class OpenAICompatibleLlmClient:
|
||||
"""保存连接参数、模型参数和可替换的 HTTP transport。"""
|
||||
if not base_url:
|
||||
raise ValueError("必须配置 LLM base_url")
|
||||
if not api_key:
|
||||
raise ValueError("必须配置 LLM api_key")
|
||||
if not model:
|
||||
raise ValueError("必须配置 LLM model")
|
||||
self.base_url = base_url.rstrip("/")
|
||||
@ -178,12 +176,12 @@ class OpenAICompatibleLlmClient:
|
||||
},
|
||||
],
|
||||
}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if self.api_key:
|
||||
headers["Authorization"] = f"Bearer {self.api_key}"
|
||||
response = self.transport(
|
||||
_chat_completions_url(self.base_url),
|
||||
{
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
headers,
|
||||
request_payload,
|
||||
self.timeout_sec,
|
||||
)
|
||||
|
||||
@ -2,6 +2,7 @@ from dataclasses import asdict
|
||||
|
||||
from pam_deploy_graph.agent import PamDeployAgent
|
||||
from pam_deploy_graph.checkpoint_store import redact_mapping
|
||||
from pam_deploy_graph.llm.factory import build_llm_client
|
||||
from pam_deploy_graph.llm.openai_compatible import OpenAICompatibleLlmClient
|
||||
from pam_deploy_graph.llm.rule_based import RuleBasedLlmClient
|
||||
from pam_deploy_graph.llm.validators import validate_deploy_plan
|
||||
@ -110,6 +111,45 @@ def test_openai_compatible_client_uses_base_url_api_key_and_prompt():
|
||||
assert "只输出一个 JSON 对象" in calls[0][2]["messages"][0]["content"]
|
||||
|
||||
|
||||
def test_openai_compatible_client_allows_empty_api_key():
|
||||
calls = []
|
||||
|
||||
def transport(url, headers, payload, timeout_sec):
|
||||
calls.append((url, headers, payload, timeout_sec))
|
||||
return {
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"content": (
|
||||
'{"intent":"deploy","mode_preference":"未指定",'
|
||||
'"strategy_preference":"fake","confidence":0.8}'
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
client = OpenAICompatibleLlmClient(
|
||||
base_url="https://llm.example/v1",
|
||||
api_key="",
|
||||
model="model-a",
|
||||
transport=transport,
|
||||
)
|
||||
|
||||
result = client.understand_request("部署")
|
||||
|
||||
assert result.intent == "deploy"
|
||||
assert "Authorization" not in calls[0][1]
|
||||
assert calls[0][1]["Content-Type"] == "application/json"
|
||||
|
||||
|
||||
def test_llm_factory_allows_empty_api_key_with_base_url_and_model():
|
||||
client = build_llm_client(base_url="https://llm.example/v1", model="model-a")
|
||||
|
||||
assert isinstance(client, OpenAICompatibleLlmClient)
|
||||
assert client.api_key == ""
|
||||
|
||||
|
||||
def test_openai_compatible_client_does_not_send_base_secret():
|
||||
calls = []
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user