Truy cập LLM của plugin``ctx.LLM
` là cách được hỗ trợ để plugin thực hiện cuộc gọi LLM. Hoàn thành cuộc trò chuyện, trích xuất có cấu trúc, đồng bộ hóa, không đồng bộ, có hoặc không có hình ảnh - cùng một bề mặt, cùng một cổng tin cậy, cùng thông tin xác thực thuộc sở hữu của máy chủ.
Các plugin đạt được điều này khi chúng cần làm điều gì đó liên quan đến mô hình nhưng không phải là một phần của cuộc trò chuyện của đại lý. Một cái móc đó viết lại lỗi công cụ thành thứ gì đó mà người không phải kỹ sư có thể đọc được. A bộ điều hợp cổng dịch tin nhắn gửi đến trước khi xếp hàng nó. Lệnh gạch chéo tóm tắt một đoạn dán dài. Một công việc theo lịch trình chấm điểm hoạt động của ngày hôm qua và viết một dòng vào trạng thái bảng. Bộ lọc trước quyết định xem tin nhắn có đáng để đánh thức hay không các đại lý lên cho tất cả.
Đây là những công việc mà người đại diện không nên tham gia. Họ muốn một Cuộc gọi LLM, một câu trả lời được đánh máy và sẽ được thực hiện.
Cuộc gọi nhỏ nhất có thể
result = ctx.LLM.complete(messages=[\{"role": "user", "content": "ping"}])
return result.text
`
``Đó là toàn bộ API trong một dòng. Không có chìa khóa, không có cấu hình nhà cung cấp, không
Khởi tạo SDK. Plugin chạy với bất kỳ nhà cung cấp nào và
mô hình mà người dùng hiện đang sử dụng — khi họ chuyển đổi nhà cung cấp,
plugin tự động theo dõi chúng.
## Ví dụ trò chuyện đầy đủ hơn
`Python
result = ctx.LLM.complete(
messages=[
\{"role": "system", "content": "Rewrite errors as one short sentence a non-engineer can act on."},
\{"role": "user", "content": traceback_text},
],
max_tokens=64,
purpose="hooks.error-rewrite",
)
return result.text
`
```purpose
` là chuỗi kiểm tra dạng tự do - nó hiển thị trong
`agent.log
và trong
`result.audit
` để người vận hành có thể xem plugin nào đã tạo
gọi. Tùy chọn nhưng được khuyến nghị cho bất kỳ thứ gì thường xuyên kích hoạt.
## Đầu ra có cấu trúc
Khi plugin cần câu trả lời được nhập, hãy chuyển sang làn có cấu trúc:
`Python
result = ctx.LLM.complete_structured(
instructions="Score this support reply for urgency (0–1) and pick a category.",
input=[\{"type": "text", "text": message_body}],
JSON_schema=TRIAGE_SCHEMA,
purpose="support.triage",
temperature=0.0,
max_tokens=128,
)
if result.parsed["urgency"] > 0.8:
await dispatch_to_oncall(result.parsed["category"], message_body)
`
``Máy chủ yêu cầu đầu ra JSON từ nhà cung cấp, phân tích cú pháp cục bộ
như một phương án dự phòng, xác thực dựa trên lược đồ của bạn nếu
`JSONschema
` là
đã cài đặt và trao lại đối tượng Python trên
`result.parsed
. Nếu
mô hình không thể tạo JSON hợp lệ,
`result.parsed
` là
`None
` và
`result.text
` mang phản hồi thô.
## Làn đường này mang lại cho bạn điều gì
* **Một cuộc gọi, bốn hình dạng.**
`complete()
` để trò chuyện,``complete_structured()
` cho JSON đã nhập,
`acomplete()
` và``acomplete_structured()
` cho asyncio. Lập luận giống nhau, kết quả giống nhau
đồ vật.
* **Thông tin đăng nhập do máy chủ sở hữu.** Mã thông báo OAuth, luồng làm mới,
nhóm thông tin xác thực, ghi đè phụ trợ cho mỗi tác vụ - mọi thông tin xác thực
khái niệm Hermes đã được áp dụng. Plugin không bao giờ nhìn thấy
mã thông báo; máy chủ thực hiện cuộc gọi lại thông qua
`result.audit
.
* **Bị giới hạn.** Cuộc gọi đồng bộ hóa đơn hoặc không đồng bộ. Không phát trực tuyến, không có công cụ
vòng lặp, không có trạng thái hội thoại để quản lý. Nêu rõ đầu vào, lấy
kết quả, trả về.
* **Độ tin cậy đóng không thành công.** Một plugin bạn chưa từng định cấu hình không thể
chọn nhà cung cấp, mô hình, đại lý hoặc thông tin xác thực được lưu trữ của riêng mình. các
tư thế mặc định là "sử dụng những gì người dùng đang sử dụng." Nhà khai thác chọn tham gia
đối với các phần ghi đè cụ thể, cho mỗi plugin, trong
`config.yaml
.
## Bắt đầu nhanh
Hai plugin hoàn chỉnh bên dưới — một trò chuyện, một có cấu trúc. Cả hai tàu
bên trong một hàm
`register(ctx)
` duy nhất và không cần bên ngoài
cấu hình để chạy với bất kỳ mô hình nào mà người dùng đã kích hoạt.
### Hoàn thành trò chuyện —
/tldr
`
``` python
def register(ctx):
ctx.register_command(
name="tldr",
handler=lambda raw: _tldr(ctx, raw),
description="Summarise the supplied text in one paragraph.",
args_hint="<text>",
)
def _tldr(ctx, raw_args: str) -> str:
text = raw_args.strip()
if not text:
return "Usage: /tldr <text to summarise"
result = ctx.LLM.complete(
messages=[
\{"role": "system",
"content": "Summarise the user's text in one tight paragraph. No preamble."},
\{"role": "user", "content": text},
],
max_tokens=256,
temperature=0.3,
purpose="tldr",
)
return result.text
`
```result.text
` là phản hồi của mô hình;
`result.usage
` mang mã thông báo
đếm;
`result.provider
` và
`result.model
` mang thuộc tính.
### Trích xuất có cấu trúc —
/paste-to-tasks
`
`Python
def register(ctx):
ctx.register_command(
name="paste-to-tasks",
handler=lambda raw: _paste_to_tasks(ctx, raw),
description="Turn freeform meeting notes into structured tasks.",
args_hint="<text>",
)
_TASKS_SCHEMA = {
"type": "object",
"properties": {
"tasks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"owner": \{"type": "string"},
"action": \{"type": "string"},
"due": \{"type": "string", "description": "ISO date or empty"},
},
"required": ["action"],
},
},
},
"required": ["tasks"],
}
def _paste_to_tasks(ctx, raw_args: str) -> str:
if not raw_args.strip():
return "Usage: /paste-to-tasks <meeting notes>"
result = ctx.LLM.complete_structured(
instructions=(
"Extract concrete action items from these meeting notes. "
"One task per actionable line. If no owner is named, leave 'owner' blank."
),
input=[\{"type": "text", "text": raw_args}],
JSON_schema=_TASKS_SCHEMA,
schema_name="meeting.tasks",
purpose="paste-to-tasks",
temperature=0.0,
max_tokens=512,
)
if result.parsed is None:
return f"Couldn't parse a response. Raw output:\n\{result.text}"
lines = [f"- [\{t.get('owner') or '?'}] \{t['action']}" for t in result.parsed["tasks"]]
return "\n".join(lines) or "(no tasks found)"
`
``Ví dụ hoạt động thứ ba, lần này với đầu vào hình ảnh, nằm trong
[XPROTECTX32XPROTECTX](https://GitHub.com/NousResearch/Hermes-example-plugins/tree/main/plugin-LLM-example)
repo (repo đồng hành dành cho các plugin tham khảo - không đi kèm với
chính tác nhân Hermes). Đối với bề mặt không đồng bộ (
`acomplete()
` /
`acomplete_structured()
` với
`asyncio.gather()
), xem
[XPROTECTX36XPROTECTX](https://GitHub.com/NousResearch/Hermes-example-plugins/tree/main/plugin-LLM-async-example)
trong cùng một kho lưu trữ.
## Khi nào nên sử dụng cái nào
| Bạn muốn… | Tiếp cận |
|---|---|
| Phản hồi văn bản dạng tự do (dịch, tóm tắt, viết lại, tạo) |
complete()
` |
| Lời nhắc nhiều lượt (hệ thống + ví dụ về một vài lượt quay + người dùng) |
complete()
` |
| Một lệnh được gõ lại, được xác thực dựa trên một lược đồ |
complete_structured()
` |
| Nhập hình ảnh hoặc văn bản bằng cách nhập lại chính tả |
complete_structured()
` |
| Cuộc gọi tương tự từ mã không đồng bộ (bộ điều hợp cổng, móc không đồng bộ) |
acomplete()
` /
`acomplete_structured()
` |
Mọi thứ khác — lựa chọn nhà cung cấp, độ phân giải mô hình, xác thực, dự phòng,
thời gian chờ, định tuyến tầm nhìn - giống nhau trên cả bốn.
## Bề mặt API``ctx.LLM
` là phiên bản của
`agent.plugin_LLM.PluginLLM
.
###
`complete()
`
`Python
result = ctx.LLM.complete(
messages=[\{"role": "user", "content": "Hi"}],
provider=None, # optional, gated — Hermes provider id (e.g. "OpenRouter")
model=None, # optional, gated — whatever string that provider expects
temperature=None,
max_tokens=None,
timeout=None, # seconds
agent_id=None, # optional, gated
profile=None, # optional, gated — explicit auth-profile name
purpose="optional-audit-string",
)
# → PluginLLMCompleteResult(text, provider, model, agent_id, usage, audit)
`
`Hoàn thành trò chuyện đơn giản.
`messages
` là hình dạng OpenAI tiêu chuẩn — một
danh sách các lệnh
\{"role": "...", "content": "..."}
. Nhiều lượt
lời nhắc (hệ thống + cặp người dùng/trợ lý vài lần + người dùng cuối) hoạt động
chính xác như cách họ làm với OpenAI SDK.
provider=
` và
`model=
` độc lập và có hình dạng giống nhau
làm cấu hình chính của máy chủ (
`model.provider
+
`model.model
). Đặt
chỉ
`model=
` để sử dụng nhà cung cấp đang hoạt động của người dùng với một nhà cung cấp khác
mô hình trên đó. Đặt cả hai để chuyển đổi hoàn toàn nhà cung cấp. Hoặc là lập luận
không có sự chọn tham gia của nhà điều hành sẽ tăng
`PluginLLMTRustError
.
###
`complete_structured()
`
``` python
result = ctx.LLM.complete_structured(
instructions="What you want extracted.",
input=[
\{"type": "text", "text": "..."},
\{"type": "image", "data": b"...", "mime_type": "image/png"},
\{"type": "image", "url": "https://..."},
],
JSON_schema=\{...}, # optional — triggers parsed result + validation
JSON_mode=False, # set True without a schema to ask for JSON anyway
schema_name=None, # optional human-readable schema name
system_prompt=None,
provider=None, # optional, gated
model=None, # optional, gated
temperature=None,
max_tokens=None,
timeout=None,
agent_id=None,
profile=None,
purpose=None,
)
# → PluginLLMStructuredResult(text, provider, model, agent_id,
# usage, parsed, content_type, audit)
`
``Đầu vào là các khối văn bản hoặc hình ảnh được nhập (byte thô được mã hóa base64
dưới dạng URL
`data:
` tự động). Khi
`JSON_schema
` hoặc
`JSON_mode=True
` được cung cấp, máy chủ yêu cầu đầu ra JSON thông qua
`response_format
, phân tích cú pháp cục bộ dưới dạng dự phòng và xác thực
dựa vào lược đồ của bạn nếu
`JSONschema
` được cài đặt.
*
`result.content_type == "JSON"
` —
`result.parsed
` là một Python
đối tượng phù hợp với lược đồ của bạn.
*
`result.content_type == "text"
` — phân tích cú pháp hoặc xác thực không thành công;
kiểm tra
`result.text
` để biết phản hồi của mô hình thô.
### Không đồng bộ
``` python
result = await ctx.LLM.acomplete(messages=...)
result = await ctx.LLM.acomplete_structured(instructions=..., input=...)
`
``Các đối số và loại kết quả giống như đối tác đồng bộ hóa của chúng. sử dụng
những thứ này từ bộ điều hợp cổng, móc không đồng bộ hoặc bất kỳ mã plugin nào
đã chạy trên vòng lặp asyncio.
### Thuộc tính kết quả
`Python
@dataclass
class PluginLLMCompleteResult:
text: str # the assistant's response
provider: str # e.g. "OpenRouter", "Anthropic"
model: str # whatever the provider returned for this call
agent_id: str # whose model/auth was used
usage: PluginLLMUsage # tokens + cache + cost estimate
audit: Dict[str, Any] # plugin_id, purpose, profile`@dataclass
class PluginLLMStructuredResult(PluginLLMCompleteResult):
parsed: Optional[Any] # JSON object when content_type == "JSON"
content_type: str # "JSON" or "text"
# audit also carries schema_name when supplied
`
```usage
` mang
`input_tokens
,
`output_tokens
,
`total_tokens
,
`cache_read_tokens
,
`cache_write_tokens
` và
`cost_usd
` khi
nhà cung cấp trả về các trường đó.
## Cổng tin cậy
Hành vi mặc định là không đóng được. Không có
`plugins.entries
khối cấu hình, một plugin có thể:
* chạy bất kỳ phương pháp nào trong bốn phương pháp đối với nhà cung cấp đang hoạt động của người dùng
và người mẫu,
* đặt các đối số định hình yêu cầu (
`temperature
,
`max_tokens
,``timeout
,
`system_prompt
,
`purpose
,
`messages
,
`instructions
,``input
,
`JSON_schema
),`…và thế là xong.
`provider=
,
`model=
,
`agent_id=
` và
`profile=
các đối số tăng
`PluginLLMTRustError
` cho đến khi người vận hành chọn tham gia.
**Hầu hết các plugin không bao giờ cần phần này.** Một plugin chỉ gọi
`ctx.LLM.complete(messages=...)
` không có phần ghi đè nào chống lại
bất cứ điều gì người dùng đã hoạt động và hoạt động ở chế độ zero-config. Khối bên dưới
chỉ phù hợp khi một plugin đặc biệt muốn ghim vào một
mô hình hoặc nhà cung cấp khác với người dùng.
``` yaml
plugins:
entries:
my-plugin:
LLM:
# Allow this plugin to choose a different Hermes provider
# (must be one Hermes already knows about — same names as
#
`Hermes model
` and config.yaml model.provider).
allow_provider_override: true
# Optionally restrict which providers. Use ["*"] for any.
allowed_providers:
- OpenRouter
- Anthropic
# Allow this plugin to ask for a specific model.
allow_model_override: true
# Optionally restrict which models. Use ["*"] for any.
# Models are matched literally against whatever string the
# plugin sends — Hermes does not look anything up.
allowed_models:
- OpenAI/GPT-4o-mini
- Anthropic/Claude-3-5-haiku
# Allow cross-agent calls (rare).
allow_agent_id_override: false
# Allow the plugin to request a specific stored auth profile
# (e.g. a different OAuth account on the same provider).
allow_profile_override: false
`
``Id plugin là trường
`name:
` tệp kê khai dành cho plugin phẳng hoặc
khóa dẫn xuất đường dẫn cho các plugin lồng nhau (
`image_gen/OpenAI
,
`memory/Honcho
, v.v.).
### Cổng thực thi những gì
| Ghi đè | Mặc định | Phím cấu hình |
| --------------- | ------- | -------------------------------- |
|
`provider=
` | bị từ chối |
allow_provider_override: true
` |
| ↳ danh sách cho phép | — |
allowed_providers: [...]
` |
|
`model=
` | bị từ chối |
allow_model_override: true
` |
| ↳ danh sách cho phép | — |
allowed_models: [...]
` |
|
`agent_id=
` | bị từ chối |
allow_agent_id_override: true
` |
|
`profile=
` | bị từ chối |
allow_profile_override: true
` |
Mỗi ghi đè được kiểm soát độc lập. Cấp
`allow_model_override
**không** cũng cấp
`allow_provider_override
` — một plugin đáng tin cậy
để chọn một mô hình vẫn được ghim vào nhà cung cấp đang hoạt động của người dùng trừ khi
nó cũng nhận được cổng nhà cung cấp.
### Những gì cổng KHÔNG cần thực thi
* Đối số định hình yêu cầu -
`temperature
,
`max_tokens
,``timeout
,
`system_prompt
,
`purpose
,
`messages
,
`instructions
,``input
,
`JSON_schema
,
`schema_name
,
`JSON_mode
` — luôn là
được phép; họ không chọn thông tin đăng nhập hoặc tuyến đường.
* Tư thế từ chối mặc định có nghĩa là plugin chưa được định cấu hình vẫn có thể thực hiện được
công việc hữu ích — nó chỉ chạy ngược lại với mô hình và nhà cung cấp đang hoạt động.
Người vận hành chỉ cần nghĩ đến
`plugins.entries
` cho plugin
muốn định tuyến tốt hơn.
## Thứ mà chủ nhà sở hữu
Danh sách đầy đủ những điều
`ctx.LLM
` thực hiện cho plugin để bạn
không cần phải:* **Giải pháp của nhà cung cấp.** Đọc
`model.provider
+
`model.model
từ cấu hình của người dùng (hoặc ghi đè rõ ràng khi được tin cậy).
* **Auth.** Lấy khóa API, mã thông báo OAuth hoặc mã thông báo làm mới từ
~/.Hermes/auth.JSON
` / env, bao gồm nhóm thông tin xác thực khi
một cái đã được cấu hình. Plugin không bao giờ nhìn thấy chúng.
* **Định tuyến tầm nhìn.** Khi đầu vào hình ảnh được cung cấp và
mô hình văn bản hiện hoạt chỉ ở dạng văn bản, máy chủ sẽ quay trở lại
mô hình tầm nhìn được cấu hình tự động.
* **Chuỗi dự phòng.** Nếu nhà cung cấp chính của người dùng là 5xx hoặc 429,
yêu cầu đi qua dự phòng nhận biết tổng hợp thông thường của Hermes
trước khi nó trả về lỗi cho plugin.
* **Hết giờ.** Tôn trọng đối số
`timeout=
` của bạn, quay trở lại
Cấu hình
`auxiliary.<task.timeout
` hoặc mặc định phụ trợ toàn cầu.
* **Định hình JSON.** Gửi
`response_format
` cho nhà cung cấp khi
bạn yêu cầu JSON, sau đó phân tích lại cục bộ từ một hàng rào mã
phản hồi nếu nhà cung cấp trả lại một phản hồi.
* **Xác thực lược đồ.** Xác thực dựa trên
`JSON_schema
` của bạn khi``JSONschema
` đã được cài đặt; ghi lại một dòng gỡ lỗi và bỏ qua nghiêm ngặt
xác nhận bằng cách khác.
* **Nhật ký kiểm tra.** Mỗi cuộc gọi ghi một dòng INFO vào
`agent.log
` với
tổng số id plugin, nhà cung cấp/mô hình, mục đích và mã thông báo.
## Plugin sở hữu những gì
* **Yêu cầu hình dạng.**
`messages
` để trò chuyện,
`instructions
+
`input
cho có cấu trúc. Plugin xây dựng lời nhắc; máy chủ chạy nó.
* **Lược đồ.** Bất kỳ hình dạng nào bạn muốn quay lại. Máy chủ không suy luận
nó dành cho bạn.
* **Xử lý lỗi.**
`complete_structured()
` tăng
`ValueError
` trên
đầu vào trống và lỗi xác thực lược đồ.
`PluginLLMTRustError
kích hoạt khi cổng tin cậy từ chối ghi đè. Bất cứ điều gì khác
(nhà cung cấp 5xx, không có thông tin xác thực nào được định cấu hình, hết thời gian chờ) tăng bất cứ điều gì``auxiliary_CLIent.call_LLM()
` tăng.
* **Chi phí.** Mọi cuộc gọi đều thực hiện với nhà cung cấp dịch vụ trả phí của người dùng. Đừng
lặp trên
`complete()
` cho mọi tin nhắn cổng mà không cần suy nghĩ
về việc chi tiêu token.
## Vị trí này phù hợp với bề mặt plugin
Các phương pháp
`ctx.*
` hiện có mở rộng hệ thống con Hermes hiện có:`|
`ctx.register_tool
` | thêm một công cụ mà đại lý có thể gọi |
|
`ctx.register_platform
` | dây một bộ chuyển đổi cổng mới |
|
`ctx.register_image_gen_provider
` | thay thế phần phụ trợ image-gen |
|
`ctx.register_memory_provider
` | thay thế phần phụ trợ bộ nhớ |
|
`ctx.register_context_engine
` | thay thế máy nén bối cảnh |
|
`ctx.register_hook
` | quan sát một sự kiện trong vòng đời |
ctx.LLM
` là bề mặt đầu tiên cho phép plugin chạy tương tự
mô hình mà người dùng đang nói chuyện, *ngoài nhóm*, không có bất kỳ mô hình nào
ở trên. Đó là công việc duy nhất của nó. Nếu plugin của bạn cần đăng ký một
công cụ mà tác nhân gọi, hãy sử dụng
`register_tool
. Nếu nó cần phản ứng
đến một sự kiện trong vòng đời, hãy sử dụng
`register_hook
. Nếu nó cần phải làm
lệnh gọi mô hình riêng - vì bất kỳ lý do gì, có cấu trúc hay không -
`ctx.LLM
.
## Tham khảo
* Triển khai: [XPROTECTX143XPROTECTX](https://GitHub.com/NousResearch/Hermes-agent/blob/main/agent/plugin_LLM.py)
* Thử nghiệm: [XPROTECTX144XPROTECTX](https://GitHub.com/NousResearch/Hermes-agent/blob/main/tests/agent/test_plugin_LLM.py)
* Các plugin tham khảo (repo đồng hành):
* [XPROTECTX145XPROTECTX](https://GitHub.com/NousResearch/Hermes-example-plugins/tree/main/plugin-LLM-example) - trích xuất có cấu trúc đồng bộ hóa với đầu vào hình ảnh
* [XPROTECTX146XPROTECTX](https://GitHub.com/NousResearch/Hermes-example-plugins/tree/main/plugin-LLM-async-example) — không đồng bộ với
`asyncio.gather()
* Máy khách phụ trợ (động cơ dưới mui xe): xem
[Provider Runtime](/docs/developer-guide/provider-runtime).