Skip to content

Prompt Management

Languages: English · 中文

Agently splits a prompt into named slots. The slots compose, so you can set persistent agent context once and only fill request-specific slots per call.

Slot map

SlotWhere it ends upTypical use
role / systemsystem messagepersona, capability boundaries
infosystem or user (impl detail)background facts, inventories, tool catalogs
instructuser messagestep-by-step instructions for this kind of request
inputuser messagethe actual question or payload
outputuser message + parserthe schema you want back

Setting a slot persistently:

python
agent = (
    Agently.create_agent()
    .role("You are an Agently support assistant.", always=True)
    .info({"product": "Agently 4.x"}, always=True)
)

always=True keeps the slot at the agent level so it carries to every request the agent runs.

Setting a slot for one request:

python
result = (
    agent
    .instruct(["Reply in fewer than 80 words.", "Never invent product names."])
    .input("How do I configure a model?")
    .output({"answer": (str, "answer", True)})
    .start()
)

instruct(...) here is per-request because always=True was not passed.

Agent vs execution scope

ScopeAPI
Agent definition (persists for every future execution).define(...), .role(..., always=True), .info(..., always=True), .set_agent_prompt(key, value)
AgentExecution draft (one execution only).input(...), .output(...), .set_execution_prompt(key, value)

The slot you set last wins for that scope, so you can override agent defaults in one execution without mutating the agent. set_turn_prompt(...) and set_request_prompt(...) remain compatibility aliases for execution-local prompt writes.

YAML / JSON prompt files

Same slot model, written declaratively:

yaml
# prompts/triage.yaml
$ensure_all_keys: true
.agent:
  system: You are a ticket triage assistant.
  info:
    severities: ["P0", "P1", "P2", "P3"]
.execution:
  instruct: Classify the ticket text.
  output:
    $format: json
    severity:
      $type: str
      $desc: One of P0/P1/P2/P3
      $ensure: true
    rationale:
      $type: str
      $desc: One-line reason
      $ensure: true

Loading:

python
agent = Agently.create_agent().load_yaml_prompt("prompts/triage.yaml")

result = (
    agent
    .create_execution()
    .set_execution_prompt("input", "Login fails for all users in EU region.")
    .start()
)

load_json_prompt(...) is the same API for JSON. Both accept either a path or a raw string body. Pick one config file per prompt or stack multiple prompts with prompt_key_path="demo.output_control" to select inside a multi-prompt file.

Prompt config uses .execution for one execution. .turn and .request remain compatibility aliases for older prompt files.

$ensure_all_keys: true at the top makes all leaves required regardless of per-leaf $ensure. Use it when the entire schema must come back complete.

$format on the output block maps to the same output format setting as .output(..., format=...). Supported values are auto, json, flat_markdown, hybrid, xml_field, and yaml_literal. You can also use .format, $output_format, or .output_format when a config file needs a more explicit key.

Round-tripping

You can convert a Python-built prompt back to YAML/JSON for review or storage:

python
agent.role("You are an Agently agent.", always=True).input("Say hello.").output({
    "reply": (str, "reply", True),
})
print(agent.get_yaml_prompt())
print(agent.get_json_prompt())
print(agent.get_prompt_text())  # the rendered text the model will see

This round-trip is the canonical way to compare "what I think I'm sending" against "what the framework actually sends".

Placeholders

Inside any prompt slot, {name} references another slot by key, and ${name} is replaced by mappings={"name": "value"} at load time. Common patterns:

  • instruct: "Reply {input} politely." — pulls the request input into the instruct text.
  • ${ENV.OPENAI_API_KEY} in settings (not prompts) is replaced by the env var; prompts use ${name} with explicit mappings.
  • ${INPUT.customer}, ${INFO.policy}, and ${INSTRUCT.step} are render-time slot references. They become prompt section pointers such as [INPUT > customer] instead of copying slot values into another slot. Slot names are case-insensitive; docs use uppercase. The path after the slot name is not validated because it is only a model-facing reference label.
  • ${OUTPUT} is an alias for [OUTPUT REQUIREMENT].

To trigger placeholder substitution while loading, pass mappings=... explicitly:

python
agent.load_yaml_prompt(yaml_text, mappings={"product_name": "Agently"})

Where each layer's prompt comes from

When a request runs, Agently composes the final prompt by stacking:

  1. Agent-level slots (set with always=True or set_agent_prompt)
  2. Request-level slots (set without always=True)
  3. Slots populated by framework extensions or application code (Session injects chat history; retrieval code usually puts snippets into per-request info(...))

Use agent.get_prompt_text() to see the merged result before sending.

See also