|
@shaneutt, yesterday we had a very productive discussion with @usize and presented some of the work we are doing at IBM Research around AI skill optimization (The skillberry project https://github.com/skillberry-ai/ ). One area we are exploring is treating customer agents as black boxes and providing optimized tools, prompts, and reusable snippets through a proxy-agent layer. We developed a standalone implementation of this here: https://github.com/skillberry-ai/skillberry-agent Based on our discussion and @usize's explanation of Praxis, I think that there is a strong opportunity for collaboration. Rather than building and maintaining our own proxy infrastructure, we could potentially leverage the Praxis proxy to intercept and manipulate LLM requests and responses. Today, our system exposes a @shaneutt, could you take a look at the repository and share your thoughts on whether Praxis could be a good fit for this architecture? Possible next steps:
Ref: https://github.com/praxis-proxy/praxis/issues/354 CC'ing the relevant IBM Research team members: @OsherElhadad @aviweit @ronenl-ibm |
Replies: 7 comments
|
We appreciate the details @eranra 👍 The Skillberry approach of treating customer agents as black boxes and optimizing through a proxy layer is interesting, and there's clear overlap with what we're building. A few questions:
We've been having a weekly sync, I'll send you an invite if you would like to add this as an upcoming agenda topic. Thanks! |
|
Hi @shaneutt, Sorry for the late response—I missed the notification in my email. 🙂
From what I understood from @usize, and from reading the documentation (I haven't installed Praxis yet), there is an intention to move higher up the stack and provide both the facilities and the extension points needed to support more sophisticated pipelines like the ones we're building in the SKillberry-proxy with MCP and LangGraph. However, I see this more as an architectural direction than something that's fully realized today. I think a practical approach would be to start with a pluggable model for the MCP/LangGraph integration and use Praxis initially for request interception and context manipulation, with the heavy lifting handled by an external process. Over time, I hope (and would suggest) that Praxis evolves to allow more of this functionality to be embedded directly into the core. Another reason for this approach is the difference in development velocity between Python and Rust. It's much easier to iterate quickly in Python, although in 2026, with Claude and friends, that gap is becoming much smaller.
Unfortunately, it's all of the above. 🙂 What we do is "learn from the trajectories"—understanding what works well and what doesn't—and use that knowledge to build a collection of reusable snippets (text) and tools (executables). These may be entirely new or modifications of the originals. As a result, we dynamically modify both the available tool list and the execution context. We also allow ourselves to remove or replace parts of the context when we believe it will improve the agent's behavior (or even deliberately "confuse" the agent when appropriate for experimentation).
That's a very good question. In most cases, we're dominated by LLM latency. The calls to the LLM are significantly slower than any of the essentially deterministic processing happening in the proxy (currently implemented in Python). That said, latency is very important, and if we can demonstrate that this "black-box" approach is also efficient from a latency perspective, I think that would be valuable. The current requirement to access the Skillberry-Store which is an external remote service - may naturally push us toward using
Yes, that's what I suspected - that we'd likely need to use the Thanks for the very informative and helpful response! 🙂 Also, if possible, could you forward the invitation for the weekly meeting also to @aviweit ? @OsherElhadad @aviweit @ronenl-ibm |
Yes, please ping me on Slack and send me the email of everyone you want added 👍
ACK
Understood. Avoiding it will be preferable when feasible: we've mostly added it as fallback position for the integration of existing systems. I would like to start enumerating and fleshing out the critical needs, to see if they are generally applicable. If so, we would be open to adopting them natively in Praxis, and you might be able to avoid ext-proc? I'm going to consider this issue I want to consider it a Let me know your thoughts, and if it's OK for me to assign you to this one and consider it "in progress" according to the approach above? |
|
I wanted to share a quick update on my progress. I’ve cloned and set up Praxis on my Ubuntu environment, and implemented a simple HTTP filter that logs incoming “human” message requests and then forwards them to a RITS proxy server (OpenAI-compatible). User/agent $ ./test-litellm-praxis.sh | jq .
{
"id": "chatcmpl-1c2cf0fd-92d0-4f39-b3ca-453994b4deb5",
"created": 1781793611,
"model": "rits/openai/gpt-oss-120b",
"object": "chat.completion",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "Sure thing! Here’s a light‑hearted one for you:\n\n**Why don’t scientists trust atoms anymore?**\n\n*Because they make up everything… but they’re also great at throwing a party—after all, they love to bond!* 😄",
"role": "assistant",
"reasoning_content": "We need to respond with a happy joke. No policy issues. Just a joke.",
"provider_specific_fields": {
"refusal": null,
"reasoning_content": "We need to respond with a happy joke. No policy issues. Just a joke."
}
},
"provider_specific_fields": {
"stop_reason": null,
"token_ids": null
}
}
],
"usage": {
"completion_tokens": 77,
"prompt_tokens": 77,
"total_tokens": 154
}
}Praxis console 026-06-18T14:39:47.831860Z INFO praxis::server: starting server
2026-06-18T14:39:47.831890Z INFO pingora_core::server: Server starting
2026-06-18T14:39:47.831895Z INFO pingora_core::server: Starting services in dependency order: ["http-proxy:litellm-gateway"]
2026-06-18T14:39:47.831898Z INFO pingora_core::server: Starting service: http-proxy:litellm-gateway
2026-06-18T14:39:47.832921Z INFO praxis::watcher: config file watcher started path=config-litellm.yaml
============================================================
[HUMAN MESSAGE] Hello! Tell me a NEW joke.
============================================================
2026-06-18T14:40:09.817395Z INFO praxis::reload: building new pipelines from reloaded config
2026-06-18T14:40:09.817523Z INFO praxis::reload: config reload complete swapped=["litellm-gateway"] skipped=[]
============================================================
[HUMAN MESSAGE] Hello! Tell me a happy joke.
============================================================
^C2026-06-18T15:20:53.203617Z INFO pingora_core::server: SIGINT received, exiting
2026-06-18T15:20:53.203653Z INFO pingora_core::server: Waiting for runtimes to exit!
2026-06-18T15:20:53.203748Z INFO pingora_core::server: Waiting for service runtime http-proxy:litellm-gateway to exit
2026-06-18T15:20:53.204343Z INFO pingora_core::server: All runtimes exited, exiting nowAlso, I noticed the |
|
Hi @shaneutt, I would like to share the current progress of the POC I'm working on. I took the decision to start and integrate our agentic logic - using Praxis filters. Can you please let us know if it is a good direction? Please find questions below:
Our POC is preliminary and is currently located at: https://github.com/aviweit/praxis/tree/feature/phase3-mcp-tools-integration The Praxis YAML file that defines the filter flow can be found here: https://github.com/aviweit/praxis/blob/feature/phase3-mcp-tools-integration/examples/configs/ai/phase3-mcp-tools-integration.yaml If would be very good if you can review and provide us feedback. We noticed that there are predefined phases of filter invocation that affect their order and dependencies ("Body" and "Request" phases and corresponding ones for the response) that we will have to better understand. We would also like to share a diagram flow of the POC: and high level overview of our filters :
Thanks. |
|
Hi @aviweit, it's really awesome to see a POC like this in action. 1. Does Praxis handle HTTP fragmentation?Yes. Pingora handles chunked transfer encoding and HTTP/2 framing transparently. By the time body data reaches a Praxis filter's Praxis adds a body-mode layer on top of this ( Your POC already uses 2. Best practice to extend Praxis?Yes, through filters. The way you've approached it in the POC looks good. 3. External filters from separate repositories?Yes, and this is what we'd recommend for Skillberry-specific filters. Generated example 👇🏻 Praxis has a build-time auto-discovery mechanism designed exactly for this use case. The Here's what a separate
[package]
name = "skillberry-praxis-filters"
version = "0.1.0"
# This marker tells Praxis's build script to auto-discover this crate
[package.metadata.praxis-filters]
[dependencies]
async-trait = "0.1"
praxis-proxy-filter = "0.3"
serde = { version = "1", features = ["derive"] }
serde_yaml = { package = "yaml_serde", version = "0.10" }
# Your dependencies — only compiled when your crate is used:
reqwest = { version = "0.12", features = ["json"] }
mcp-client = "0.1"
use praxis_filter::export_filters;
mod skill_resolver;
mod vmcp_manager;
mod mcp_tools_enricher;
export_filters! {
http "skill_resolver" => skill_resolver::SkillResolverFilter::from_config,
http "vmcp_manager" => vmcp_manager::VmcpManagerFilter::from_config,
http "mcp_tools_enricher" => mcp_tools_enricher::McpToolsEnricherFilter::from_config,
}Operator usage — add one line to the Praxis server's [dependencies]
skillberry-praxis-filters = { git = "https://github.com/skillberry-ai/skillberry-praxis-filters" }Then reference filters by name in YAML exactly as you do now. Rebuild and run — Praxis's Why this matters for your POC: Your current branch adds It also decouples your release cadence from Praxis's — you can iterate on filter logic, update MCP client versions, and release independently. Things to look at in the POC
Re: Filter PhasesEarlier Claude assisted version of this comment managed to explain it incorrectly, which is a sign to me that we should include comments that spell it out better for agents. In short, as with e.g., https://github.com/praxis-proxy/praxis/blob/main/filter/src/pipeline/http.rs#L124 the filters are run against each phase in serial. Request filters are run in the order they were specified in. Response filters run in reverse order as per: https://github.com/praxis-proxy/praxis/blob/main/filter/src/pipeline/http.rs#L86 |
|
Hi @usize , Thanks a lot for the reply and comments. I started to move some of the work to a new repository: https://github.com/skillberry-ai/skillberry-praxis-filters. I will take your recommendations into account and will update on how it goes. Thanks. |
Hi @aviweit, it's really awesome to see a POC like this in action.
1. Does Praxis handle HTTP fragmentation?
Yes. Pingora handles chunked transfer encoding and HTTP/2 framing transparently. By the time body data reaches a Praxis filter's
on_request_body/on_response_bodyhooks, chunked framing has already been stripped so your filter receives rawByteschunks.Praxis adds a body-mode layer on top of this (
BodyMode):Your POC already uses
StreamBuffermode correctly in the filters that need the full body. So you don't need to worry about fragmentation.2. Best practice to extend Praxis?
Yes, through filters. The way you've approached it in the POC looks good.
3. External filters from sepa…