NL → GoalSpec Interpreter#

LangGOAP’s GoalInterpreter converts natural language requests into formal GoalSpec objects using any LangChain chat model that supports structured output.

"Generate a report under $5"
        ↓
GoalInterpreter.interpret()
        ↓
GoalSpec(conditions={"report_complete": True},
         constraints=(ConstraintSpec(key="cost_usd", max=5.0),))

This notebook demonstrates the interpreter in isolation — no GOAP execution.

Setup#

Define a simple action catalog and create the interpreter.

from langchain_openai import ChatOpenAI

from langgoap import ActionSpec, GoalInterpreter

# Define available actions — the interpreter uses these to ground its output
actions = [
    ActionSpec(
        name="fetch_data",
        preconditions={"has_source": True},
        effects={"data_fetched": True},
        resources={"cost_usd": 0.5, "api_calls": 1},
        metadata={"description": "Fetch raw data from the configured source"},
    ),
    ActionSpec(
        name="clean_data",
        preconditions={"data_fetched": True},
        effects={"data_clean": True},
        resources={"cost_usd": 0.1},
        metadata={"description": "Validate and clean the raw data"},
    ),
    ActionSpec(
        name="generate_report",
        preconditions={"data_clean": True},
        effects={"report_complete": True},
        resources={"cost_usd": 1.0, "tokens": 500},
        metadata={"description": "Generate a formatted report from clean data"},
    ),
]

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
interpreter = GoalInterpreter(
    llm=llm,
    actions=actions,
)

Basic Interpretation#

Convert a simple request into a GoalSpec.

goal = interpreter.interpret("Generate a report from the data")

print(f"GoalSpec: {goal}")
print(f"Conditions: {dict(goal.conditions)}")
print(f"Constraints: {goal.constraints}")
print(f"Objectives: {goal.objectives}")
GoalSpec: GoalSpec(conditions={'report_complete': True})
Conditions: {'report_complete': True}
Constraints: ()
Objectives: None

With Budget Constraints#

Budget language like “under $5” is extracted as a ConstraintSpec.

goal = interpreter.interpret("Generate a report, keeping costs under $5")

print(f"Conditions: {dict(goal.conditions)}")
print(f"Constraints: {goal.constraints}")
for c in goal.constraints:
    print(f"  {c.key}: max={c.max}, min={c.min}, weight={c.weight}")
Conditions: {'report_complete': True}
Constraints: (ConstraintSpec(key='cost_usd', max=5.0, min=None, weight=1.0, level='hard'),)
  cost_usd: max=5.0, min=None, weight=1.0

With Optimization Objectives#

Language like “cheapest” or “minimize cost” is extracted as an optimization objective.

goal = interpreter.interpret("Generate the cheapest possible report")

print(f"Conditions: {dict(goal.conditions)}")
print(f"Objectives: {dict(goal.objectives) if goal.objectives else None}")
Conditions: {'report_complete': True}
Objectives: {'cost_usd': <ObjectiveDirection.MINIMIZE: 'minimize'>}

Debugging with interpret_raw()#

interpret_raw() returns the InterpretedGoal with the LLM’s reasoning field preserved — useful for debugging and transparency.

raw = interpreter.interpret_raw("Generate a detailed report under $5, minimizing token usage")

print(f"Reasoning: {raw.reasoning}")
print(f"Conditions: {raw.conditions}")
print(f"Constraints: {raw.constraints}")
print(f"Objectives: {raw.objectives}")
Reasoning: The request specifies generating a detailed report while ensuring the total cost does not exceed $5 and aims to minimize token usage.
Conditions: {'report_complete': True}
Constraints: [InterpretedConstraint(key='cost_usd', max=5.0, min=None, weight=1.0, level='hard')]
Objectives: [InterpretedObjective(metric='tokens', direction='minimize')]

Custom System Prompt#

Override the default system prompt for domain-specific interpretation. The template must contain {action_catalog} and {world_state} placeholders.

custom_prompt = """\
You are interpreting user requests for a data pipeline system.

Available pipeline steps:
{action_catalog}

Current pipeline state:
{world_state}

Extract the user's desired end-state as **conditions** (key-value pairs using
the condition keys from the action effects above), any budget constraints, and
optimization preferences.
"""

custom_interpreter = GoalInterpreter(
    llm=llm,
    actions=actions,
    system_prompt=custom_prompt,
)
goal = custom_interpreter.interpret("Generate a complete report from the data")
print(f"GoalSpec: {goal}")