Nội bộ vòng lặp đại lý
Công cụ điều phối cốt lõi là lớp AIAgent của run_agent.py — khoảng 9.200 dòng xử lý mọi thứ từ lắp ráp nhanh chóng đến gửi công cụ đến chuyển đổi dự phòng của nhà cung cấp.
Trách nhiệm cốt lõi
AIAgent chịu trách nhiệm:
- Tập hợp các lược đồ công cụ và nhắc nhở hệ thống hiệu quả thông qua
prompt_builder.py - Chọn đúng chế độ nhà cung cấp/API (chat_completions, codex_responses, anthropic_messages)
- Thực hiện cuộc gọi mô hình bị gián đoạn với hỗ trợ hủy
- Thực hiện các lệnh gọi công cụ (tuần tự hoặc đồng thời thông qua nhóm luồng)
- Duy trì lịch sử hội thoại ở định dạng tin nhắn OpenAI
- Xử lý việc nén, thử lại và chuyển đổi mô hình dự phòng
- Theo dõi ngân sách lặp lại giữa các đại lý cha và con
- Xóa bộ nhớ liên tục trước khi bối cảnh bị mất
Hai điểm vào
# Simple interface — returns final response string
response = agent.chat("Fix the bug in main.py")
# Full interface — returns dict with messages, metadata, usage stats
result = agent.run_conversation(
user_message="Fix the bug in main.py",
system_message=None, # auto-built if omitted
conversation_history=None, # auto-loaded from session if omitted
task_id="task_abc123"
)
chat() là một trình bao bọc mỏng xung quanh run_conversation() trích xuất trường final_response từ lệnh kết quả.
Chế độ API
Hermes hỗ trợ ba chế độ thực thi API, được giải quyết từ việc lựa chọn nhà cung cấp, đối số rõ ràng và chẩn đoán URL cơ sở:
| Chế độ API | Được sử dụng cho | Loại khách hàng |
|---|---|---|
chat_hoàn thành | Điểm cuối tương thích với OpenAI (OpenRouter, tùy chỉnh, hầu hết các nhà cung cấp) | openai.OpenAI |
codex_responses | OpenAI Codex / API phản hồi | openai.OpenAI với định dạng Phản hồi |
thông điệp nhân loại | API thông điệp nhân loại bản địa | anthropic.Anthropic thông qua bộ chuyển đổi |
Chế độ này xác định cách định dạng thông báo, cách cấu trúc lệnh gọi công cụ, cách phân tích cú pháp phản hồi và cách hoạt động của bộ nhớ đệm/truyền phát. Cả ba đều hội tụ về cùng một định dạng thông báo nội bộ (các lệnh role/content/tool_calls kiểu OpenAI) trước và sau lệnh gọi API.
Thứ tự phân giải chế độ:
- Hàm tạo
api_moderõ ràng (mức độ ưu tiên cao nhất) - Phát hiện dành riêng cho nhà cung cấp (ví dụ: nhà cung cấp
anthropic→anthropic_messages) - Chẩn đoán URL cơ sở (ví dụ:
api.anthropic.com→anthropic_messages) - Mặc định:
chat_completions
Xoay vòng đời
Mỗi lần lặp của vòng lặp tác nhân tuân theo trình tự sau:
run_conversation()
1. Generate task_id if not provided
2. Append user message to conversation history
3. Build or reuse cached system prompt (prompt_builder.py)
4. Check if preflight compression is needed (>50% context)
5. Build API messages from conversation history
- chat_completions: OpenAI format as-is
- codex_responses: convert to Responses API input items
- anthropic_messages: convert via anthropic_adapter.py
6. Inject ephemeral prompt layers (budget warnings, context pressure)
7. Apply prompt caching markers if on Anthropic
8. Make interruptible API call (_api_call_with_interrupt)
9. Parse response:
- If tool_calls: execute them, append results, loop back to step 5
- If text response: persist session, flush memory if needed, return
Định dạng tin nhắn
Tất cả các tin nhắn đều sử dụng định dạng tương thích với OpenAI trong nội bộ:
{"role": "system", "content": "..."}
{"role": "user", "content": "..."}
{"role": "assistant", "content": "...", "tool_calls": [...]}
{"role": "tool", "tool_call_id": "...", "content": "..."}
Nội dung lý luận (từ các mô hình hỗ trợ tư duy mở rộng) được lưu trữ trong assistant_msg["reasoning"] và được hiển thị tùy ý thông qua reasoning_callback.
Quy tắc luân phiên tin nhắn
Vòng lặp tác nhân thực thi việc luân phiên vai trò thông báo nghiêm ngặt:
- Sau thông báo hệ thống:
Người dùng → Trợ lý → Người dùng → Trợ lý → ... - Trong khi gọi công cụ:
Trợ lý (với tool_calls) → Công cụ → Công cụ → ... → Trợ lý - Không bao giờ hai tin nhắn trợ lý liên tiếp
- Không bao giờ hai tin nhắn của người dùng liên tiếp
- Chỉ vai trò
toolcó thể có các mục liên tiếp (kết quả của công cụ song song)
Nhà cung cấp xác thực các trình tự này và sẽ từ chối các lịch sử không đúng định dạng.
Lệnh gọi API bị gián đoạn
Các yêu cầu API được gói trong _api_call_with_interrupt() chạy lệnh gọi HTTP thực tế trong một luồng nền trong khi theo dõi một sự kiện gián đoạn:
┌──────────────────────┐ ┌──────────────┐
│ Main thread │ │ API thread │
│ wait on: │────▶│ HTTP POST │
│ - response ready │ │ to provider │
│ - interrupt event │ └──────────────┘
│ - timeout │
└──────────────────────┘
Khi bị gián đoạn (người dùng gửi tin nhắn mới, lệnh /stop hoặc tín hiệu):
- Chuỗi API bị hủy (phản hồi bị loại bỏ)
- Tác nhân có thể xử lý đầu vào mới hoặc tắt sạch
- Không có phản hồi một phần nào được đưa vào lịch sử hội thoại
Thực thi công cụ
Tuần tự và Đồng thời
Khi mô hình trả về các lệnh gọi công cụ:
- Cuộc gọi công cụ đơn → được thực thi trực tiếp trong luồng chính
- Nhiều lệnh gọi công cụ → được thực thi đồng thời thông qua
ThreadPoolExecutor - Ngoại lệ: các công cụ được đánh dấu là tương tác (ví dụ:
clarify) buộc thực hiện tuần tự - Kết quả được chèn lại theo thứ tự gọi công cụ ban đầu bất kể thứ tự hoàn thành
Luồng thực thi
for each tool_call in response.tool_calls:
1. Resolve handler from tools/registry.py
2. Fire pre_tool_call plugin hook
3. Check if dangerous command (tools/approval.py)
- If dangerous: invoke approval_callback, wait for user
4. Execute handler with args + task_id
5. Fire post_tool_call plugin hook
6. Append {"role": "tool", "content": result} to history
Công cụ cấp đại lý
Một số công cụ bị chặn bởi run_agent.py trước khi đạt đến handle_function_call():
| Công cụ | Tại sao bị chặn |
|---|---|
việc cần làm | Đọc/ghi trạng thái tác vụ cục bộ của tác nhân |
ký ức | Ghi vào các tập tin bộ nhớ liên tục có giới hạn ký tự |
phiên_tìm kiếm | Truy vấn lịch sử phiên thông qua phiên DB của đại lý |
đại biểu_task | Sinh ra (các) tác nhân phụ với bối cảnh biệt lập |
Những công cụ này trực tiếp sửa đổi trạng thái tác nhân và trả về kết quả của công cụ tổng hợp mà không cần thông qua sổ đăng ký.
Bề mặt gọi lại
AIAgent hỗ trợ các lệnh gọi lại dành riêng cho nền tảng cho phép tiến trình theo thời gian thực trong tích hợp CLI, cổng và ACP:
| Gọi lại | Khi bị sa thải | Được sử dụng bởi |
|---|---|---|
tool_progress_callback | Trước/sau mỗi lần thực hiện công cụ | CLI spinner, thông báo tiến trình cổng |
suy nghĩ_gọi lại | Khi người mẫu bắt đầu/ngưng suy nghĩ | Chỉ báo CLI "suy nghĩ..." |
lý luận_gọi lại | Khi mô hình trả về nội dung suy luận | Hiển thị lý luận CLI, khối lý luận cổng |
làm rõ_gọi lại | Khi công cụ clarify được gọi | Lời nhắc đầu vào CLI, thông báo tương tác cổng |
bước_gọi lại | Sau mỗi lượt đại lý hoàn thành | Theo dõi bước cổng, tiến trình ACP |
stream_delta_callback | Mỗi mã thông báo phát trực tuyến (khi được bật) | Hiển thị phát trực tuyến CLI |
tool_gen_callback | Khi lệnh gọi công cụ được phân tích cú pháp từ luồng | Xem trước công cụ CLI trong spinner |
trạng thái_gọi lại | Thay đổi trạng thái (suy nghĩ, thực thi, v.v.) | Cập nhật trạng thái ACP |
Hành vi ngân sách và dự phòng
Ngân sách lặp lại
Tác nhân theo dõi các lần lặp lại thông qua IterationBudget:
- Mặc định: 90 lần lặp (có thể định cấu hình qua
agent.max_turns) - Được chia sẻ giữa các đại lý gốc và đại lý con — một đại lý phụ tiêu thụ từ ngân sách của đại lý gốc
- Áp lực ngân sách hai tầng thông qua
_get_budget_warning(): - Ở mức sử dụng trên 70% (cấp thận trọng): thêm
[NGÂN SÁCH: Lặp lại X/Y. N lần lặp còn lại. Bắt đầu hợp nhất công việc của bạn.]đến kết quả công cụ cuối cùng - Ở mức sử dụng trên 90% (cấp cảnh báo): thêm
[CẢNH BÁO NGÂN SÁCH: Lặp lại X/Y. Chỉ còn lại N lần lặp. Cung cấp phản hồi cuối cùng của bạn NGAY BÂY GIỜ.] - Khi đạt 100%, đại lý dừng và trả về bản tóm tắt công việc đã thực hiện
Mô hình dự phòng
Khi mô hình chính bị lỗi (giới hạn tốc độ 429, lỗi máy chủ 5xx, lỗi xác thực 401/403):
- Kiểm tra danh sách
fallback_providerstrong config - Thử từng phương án dự phòng theo thứ tự
- Khi thành công, hãy tiếp tục cuộc trò chuyện với nhà cung cấp mới
- Vào ngày 401/403, hãy thử làm mới thông tin xác thực trước khi vượt qua
Hệ thống dự phòng cũng bao gồm các tác vụ phụ trợ một cách độc lập — mỗi tác vụ trực quan, nén, trích xuất web và tìm kiếm theo phiên đều có chuỗi dự phòng riêng có thể định cấu hình thông qua phần cấu hình phụ trợ.*.
Nén và kiên trì
Khi quá trình nén được kích hoạt
- Preflight (trước lệnh gọi API): Nếu cuộc hội thoại vượt quá 50% cửa sổ ngữ cảnh của mô hình
- Tự động nén cổng: Nếu cuộc trò chuyện vượt quá 85% (tích cực hơn, chạy giữa các lượt)
Điều gì xảy ra trong quá trình nén
- Bộ nhớ được xóa vào đĩa trước (ngăn ngừa mất dữ liệu)
- Các lượt hội thoại giữa được tóm tắt thành một bản tóm tắt ngắn gọn
- N tin nhắn cuối cùng được giữ nguyên (
compression.protect_last_n, mặc định: 20) - Các cặp thông báo cuộc gọi/kết quả công cụ được giữ cùng nhau (không bao giờ tách rời)
- ID dòng phiên mới được tạo (nén tạo ra phiên "con")
Sự kiên trì của phiên
Sau mỗi lượt:
- Tin nhắn được lưu vào kho phiên (SQLite via
hermes_state.py) - Các thay đổi về bộ nhớ được xóa thành
MEMORY.md/USER.md - Phiên này có thể được tiếp tục lại sau thông qua
/resumehoặchermes chat --resume
Tệp nguồn chính
| Tập tin | Mục đích |
|---|---|
run_agent.py | Lớp AIAgent - vòng lặp tác nhân hoàn chỉnh (~ 9.200 dòng) |
agent/Prompt_builder.py | Hệ thống nhắc nhở từ trí nhớ, kỹ năng, ngữ cảnh, tính cách |
tác nhân/bối cảnh_compressor.py | Thuật toán nén hội thoại |
agent/Prompt_caching.py | Dấu hiệu bộ nhớ đệm nhanh chóng của con người và số liệu bộ nhớ đệm |
tác nhân/phụ_client.py | Ứng dụng khách LLM phụ trợ cho các nhiệm vụ phụ (tầm nhìn, tóm tắt) |
model_tools.py | Bộ sưu tập lược đồ công cụ, công văn handle_function_call() |