Compute
Deploy LangChain agents as Functions with persistent memory.
LangChain agents that call tools, browse the web, or execute code benefit from running in isolated Chalk Compute workloads with dedicated compute and network access.
This tutorial deploys a function-shaped LangChain ReAct agent that uses tool-calling to answer research questions, with an optional volume-backed function for persistent state.
Create agent.py — a self-contained LangChain agent implementation used by the Function:
# agent.py
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
from langchain_community.tools import DuckDuckGoSearchRun
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [DuckDuckGoSearchRun()]
prompt = PromptTemplate.from_template(
"Answer the following question using the tools available to you.\n\n"
"Tools: {tools}\nTool names: {tool_names}\n\n"
"Question: {input}\n{agent_scratchpad}"
)
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)Create answer.py:
# answer.py
import chalkcompute
from chalkcompute import Image, Secret
agent_image = (
Image.base("python:3.12-slim")
.pip_install([
"langchain",
"langchain-openai",
"langchain-community",
"duckduckgo-search",
])
.add_local_file("agent.py", "/app/agent.py")
.workdir("/app")
)
@chalkcompute.function(
name="langchain-answer",
image=agent_image,
secrets=[Secret.from_env("OPENAI_API_KEY")],
min_instances=0,
max_instances=1,
)
def answer(question: str) -> str:
from agent import executor
return executor.invoke({"input": question})["output"]
# deploy_langchain.py
from answer import answer
answer.deploy()
answer.wait_ready()
print(answer.remote("What is Chalk?"))python deploy_langchain.py
# Chalk is a feature platform for building and serving machine learning systems.Once the function is ready, invoke it remotely:
from answer import answer
print(answer.remote("What is the capital of France?"))
# The capital of France is Paris.LangChain agents can persist conversation history or vector store data across restarts
using a Volume. Create agent_memory.py:
import uuid
import chalkcompute
from chalkcompute import Image, Secret
memory_image = (
Image.base("python:3.12-slim")
.pip_install([
"langchain-openai",
"chromadb",
])
)
@chalkcompute.function(
name="langchain-memory-answer",
image=memory_image,
secrets=[Secret.from_env("OPENAI_API_KEY")],
volumes=[("agent-memory", "/app/memory")],
min_instances=0,
max_instances=1,
)
def answer(question: str, session_id: str) -> str:
import chromadb
from langchain_openai import ChatOpenAI
client = chromadb.PersistentClient(path="/app/memory")
collection = client.get_or_create_collection("conversation-history")
history = collection.get(
where={"session_id": session_id},
include=["documents"],
)["documents"]
prompt = "Answer the question using this conversation history:\n"
prompt += "\n".join(history)
prompt += f"\nUser: {question}"
response = ChatOpenAI(model="gpt-4o").invoke(prompt)
collection.add(
ids=[str(uuid.uuid4())],
documents=[f"User: {question}\nAssistant: {response.content}"],
metadatas=[{"session_id": session_id}],
)
return response.contentDeploy and invoke the function with an explicit session ID:
from agent_memory import answer
answer.deploy()
answer.wait_ready()
print(answer.remote("What did we discuss?", session_id="session-123"))The volume at /app/memory survives function instance restarts. The explicit
session_id keeps separate conversations from sharing history.
This example builds a LangChain agent tool that receives a financial transaction, enriches it with features from Chalk, runs a PyTorch risk model, and escalates high-risk transactions to a Kinesis review queue.
Assume your Chalk project defines features like these:
from chalk.features import features, Features
@features
class Transaction:
id: str
merchant_id: str
amount: float
merchant_category: str
merchant_risk_tier: int
customer_avg_spend_30d: float
customer_transaction_count_7d: int
country_code: strCreate risk_tool.py — a LangChain tool that queries Chalk, scores the transaction,
and posts flagged results to Kinesis:
# risk_tool.py
import json
import boto3
import torch
import torch.nn as nn
from chalkpy import ChalkClient
from langchain_core.tools import tool
RISK_THRESHOLD = 0.85
KINESIS_STREAM = "transaction-review-queue"
chalk = ChalkClient()
kinesis = boto3.client("kinesis", region_name="us-east-1")
class RiskModel(nn.Module):
def __init__(self) -> None:
super().__init__()
self.net = nn.Sequential(
nn.Linear(4, 32),
nn.ReLU(),
nn.Linear(32, 1),
nn.Sigmoid(),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.net(x)
# Load pre-trained weights
model = RiskModel()
model.load_state_dict(torch.load("/app/models/risk_model.pt", weights_only=True))
model.eval()
@tool
def score_transaction(transaction_id: str) -> str:
"""Score a financial transaction for fraud risk.
Retrieves enriched features from Chalk, runs a risk model,
and escalates to a review queue if the score exceeds the threshold.
"""
# 1. Query Chalk for enriched transaction features
result = chalk.query(
input={"transaction.id": transaction_id},
output=[
"transaction.amount",
"transaction.merchant_risk_tier",
"transaction.customer_avg_spend_30d",
"transaction.customer_transaction_count_7d",
"transaction.merchant_category",
"transaction.country_code",
],
)
amount = result.get_feature_value("transaction.amount")
merchant_risk_tier = result.get_feature_value("transaction.merchant_risk_tier")
avg_spend = result.get_feature_value("transaction.customer_avg_spend_30d")
txn_count = result.get_feature_value("transaction.customer_transaction_count_7d")
merchant_category = result.get_feature_value("transaction.merchant_category")
country = result.get_feature_value("transaction.country_code")
# 2. Run the risk model
features = torch.tensor([[
amount / max(avg_spend, 1.0), # spend ratio
float(merchant_risk_tier),
float(txn_count),
amount,
]])
with torch.no_grad():
risk_score = model(features).item()
# 3. Escalate if above threshold
if risk_score > RISK_THRESHOLD:
kinesis.put_record(
StreamName=KINESIS_STREAM,
Data=json.dumps({
"transaction_id": transaction_id,
"risk_score": round(risk_score, 4),
"amount": amount,
"merchant_category": merchant_category,
"country": country,
"reason": "automated_risk_score_exceeded",
}),
PartitionKey=transaction_id,
)
return (
f"Transaction {transaction_id}: risk score {risk_score:.2%} "
f"EXCEEDS threshold. Escalated to review queue."
)
return (
f"Transaction {transaction_id}: risk score {risk_score:.2%}. "
f"Below threshold — no action required."
)# fraud_review.py
import chalkcompute
from chalkcompute import Image, Secret
review_image = (
Image.debian_slim("3.12")
.pip_install([
"langchain",
"langchain-openai",
"chalkpy",
"torch",
"boto3",
])
.add_local_file("risk_tool.py", "/app/risk_tool.py")
.workdir("/app")
)
@chalkcompute.function(
name="fraud-review",
image=review_image,
secrets=[
Secret.from_env("OPENAI_API_KEY"),
Secret.from_env("CHALK_CLIENT_ID"),
Secret.from_env("CHALK_CLIENT_SECRET"),
],
volumes=[("risk-models", "/app/models")],
min_instances=0,
max_instances=1,
)
def review(transaction_id: str) -> str:
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
from risk_tool import score_transaction
llm = ChatOpenAI(model="gpt-4o", temperature=0)
prompt = PromptTemplate.from_template(
"You are a fraud analyst assistant. Use the score_transaction tool "
"to evaluate transactions when asked.\n\n"
"Tools: {tools}\nTool names: {tool_names}\n\n"
"Question: {input}\n{agent_scratchpad}"
)
agent = create_react_agent(llm, [score_transaction], prompt)
executor = AgentExecutor(agent=agent, tools=[score_transaction], verbose=True)
result = executor.invoke({
"input": f"Score transaction {transaction_id} for fraud risk."
})
return result["output"]from chalkcompute import Volume
vol = Volume("risk-models")
vol.put_file("risk_model.pt", open("risk_model.pt", "rb").read())
from fraud_review import review
review.deploy()
review.wait_ready()
print(review.remote("txn_8a3f2c"))Query the agent:
from fraud_review import review
print(review.remote("txn_8a3f2c"))
# Transaction txn_8a3f2c: risk score 92.31% EXCEEDS threshold. Escalated to review queue.